This commit is contained in:
p-w-rs
2022-09-21 12:04:48 -05:00
parent 9e1ad48346
commit 6d881b3edd
75 changed files with 3681 additions and 113 deletions

View File

@@ -0,0 +1,12 @@
CC=gcc
CFLAGS=-Wall -Wextra -g -pthread
BINS=$(patsubst %.c,%,$(wildcard *.c))
all: $(BINS)
clean:
rm -f $(BINS)
%: %.c
$(CC) $(CFLAGS) -o $@ $<

View File

@@ -0,0 +1,27 @@
# pthread examples
CS3841 examples using the pthread library to create POSIX threads
* pthreads1.c - Shows how to create and wait for single thread (beyond the main thread)
* pthreads2.c - Shows how to create and wait for multple threads (beyond the main thread)
Threads prints out its thread ID and process ID
Shows that threads share the same process ID but all have their own thread ID
* pthreads3.c - Shows how to pass parameter values to thread routines
* pthreads4.c - Shows how to pass parameter values to thread routines
The threads dereference the pointer passed to the thread routine to demonstrate that memory is shared between all threads
* pthreads5.c - Shows a problem that can happen with parameters passed to thread routines due to the fact that the parameter must be a pointer
The referenced location must be valid for the entire life of the thread
NOTE: Context switches between threads can happen when unexpected
* pthreads6.c - Shows the problems that can happen due to the fact that thread routine parameters are pointers to memory locations
Threads can easily affect other threads memory
NOTE: Context switches between threads can happen when unexpected
* pthreads\_race.c - Shows a "race condition" when multiple threads try to race to modify a global value
Due to unpredictable behavior in context switching the value of global\_value does not result in what is expected
* pthreads\_race\_atomic.c - Uses an atomic add instruction to prevent the race condition that can happen when multiple threads modify a global value at the same time

View File

@@ -0,0 +1,48 @@
/*
* pthreads1.c - Shows how to create and wait for single
* thread (beyond the main thread)
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int global_value = 10;
// thread_routine
// writes to a global variable - shows that
// global data is shared between threads
//
// NOTE: that parameters and return value are pointers
void* thread_routine()
{
for(int i = 0; i < 10; i++) {
printf("THREAD READS GLOBAL VALUE: %d\n", global_value);
global_value++;
sleep(1);
}
return NULL;
}
int main()
{
// Create a thread
pthread_t thr_id;
if(pthread_create(&thr_id, NULL, thread_routine, NULL) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
// Write to global data
for(int i = 0; i < 10; i++) {
printf("PARENT READS GLOBAL: %d\n", global_value);
sleep(1);
}
// Wait for thread to finish
pthread_join(thr_id, NULL);
// Return success
return 0;
}

View File

@@ -0,0 +1,52 @@
/*
* pthreads2.c - Shows how to create and wait for multple
* threads (beyond the main thread)
* Threads prints out its thread ID and process ID.
* Shows that threads share the same process ID
* but all have their own thread ID
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int global_value = 10;
// thread_routine
// writes to a global variable - shows that
// global data is shared between threads
//
// NOTE: that parameters and return value are pointers
void* thread_routine()
{
for(int i = 0; i < 10; i++) {
printf("%lu %d: THREAD READS GLOBAL VALUE: %d\n", pthread_self(), getpid(), global_value);
global_value++;
sleep(1);
}
return NULL;
}
int main()
{
// Create 5 threads
pthread_t thr_id[5];
for(int i = 0; i < 5; i++) {
if(pthread_create(&thr_id[i], NULL, thread_routine, NULL) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
}
// Wait for all threads to finish
for(int i = 0; i < 5; i++) {
pthread_join(thr_id[i], NULL);
}
// Print out final value of global data
printf("%lu %d PARENT READS GLOBAL: %d\n", pthread_self(), getpid(), global_value);
// Return success
return 0;
}

View File

@@ -0,0 +1,60 @@
/*
* pthreads3.c - Shows how to pass parameter values to thread routines
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Function to check if a number is prime
// Returns 1 if prime, 0 if not prime
int is_prime(int v)
{
for(int i = 2; i < v; i++) {
if(v % i == 0) {
return 0;
}
}
return 1;
}
// Thread routine
// calls is_prime to check if the input argument is prime
//
// NOTE: that parameters and return value are pointers
void* thread_routine(void* args)
{
int* val = (int*)args;
if(is_prime(*val)) {
printf("THREAD %lu FOUND that %d is prime\n", pthread_self(), *val);
} else {
printf("THREAD %lu FOUND that %d is not prime\n", pthread_self(), *val);
}
return NULL;
}
int main()
{
int val1 = 2;
int val2 = 100;
// Create 2 threads, passing a different value to each
pthread_t thr1;
pthread_t thr2;
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
// Wait for the threads to finish
pthread_join(thr1, NULL);
pthread_join(thr2, NULL);
// Return success
return 0;
}

View File

@@ -0,0 +1,72 @@
/*
* pthreads4.c - Shows how to pass parameter values to thread routines
* The threads dereference the pointer passed to the
* thread routine to demonstrate that memory is shared
* between all threads
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Function to check if a number is prime
// Returns 1 if prime, 0 if not prime
int is_prime(int v)
{
for(int i = 2; i < v; i++) {
if(v % i == 0) {
return 0;
}
}
return 1;
}
// Thread routine
// calls is_prime to check if the input argument is prime
// Modifies the input parameter by dereferencing the pointer
//
// NOTE: that parameters and return value are pointers
void* thread_routine(void* args)
{
int* val = (int*)args;
if(is_prime(*val)) {
printf("THREAD %lu FOUND that %d is prime\n", pthread_self(), *val);
*val = 1;
} else {
printf("THREAD %lu FOUND that %d is not prime\n", pthread_self(), *val);
*val = 0;
}
return NULL;
}
int main()
{
int val1 = 2;
int val2 = 100;
// Print out the values before creating threads
printf("Parent val1=%d val2=%d\n", val1, val2);
// Create 2 threads
pthread_t thr1;
pthread_t thr2;
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
// Wait for the threads to finish
pthread_join(thr1, NULL);
pthread_join(thr2, NULL);
// Print out the final values
printf("Parent val1=%d val2=%d\n", val1, val2);
// Return success
return 0;
}

View File

@@ -0,0 +1,66 @@
/*
* pthreads5.c - Shows a problem that can happen with parameters
* passed to thread routines due to the fact that
* the parameter must be a pointer. The referenced
* location must be valid for the entire life of the
* thread.
*
* NOTE: Context switches between threads can happen when unexpected
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Function to check if a number is prime
// Returns 1 if prime, 0 if not prime
int is_prime(int v)
{
for(int i = 2; i < v; i++) {
if(v % i == 0) {
return 0;
}
}
return 1;
}
// Thread routine
// calls is_prime to check if the input argument is prime
//
// NOTE: that parameters and return value are pointers
void* thread_routine(void* args)
{
int* val = (int*)args;
if(is_prime(*val)) {
printf("THREAD %lu FOUND that %d is prime\n", pthread_self(), *val);
} else {
printf("THREAD %lu FOUND that %d is not prime\n", pthread_self(), *val);
}
return NULL;
}
// start_thread
// Creates a new thread and returns the thread ID
//
// NOTE: the parameter to the thread is created on the stack
// the address becomes invalid when the function returns
pthread_t start_thread(int val)
{
pthread_t thr;
printf("Before thread creation val=%d\n", val);
if(pthread_create(&thr, NULL, thread_routine, (void*)&val) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
return thr;
}
int main()
{
pthread_t thr1 = start_thread(2);
pthread_t thr2 = start_thread(100);
pthread_join(thr1, NULL);
pthread_join(thr2, NULL);
return 0;
}

View File

@@ -0,0 +1,68 @@
/*
* pthreads6.c - Shows the problems that can happen due to the fact
* that thread routine parameters are pointers to memory
* locations. Threads can easily affect other threads
* memory.
*
* NOTE: Context switches between threads can happen when unexpected
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Function to check if a number is prime
// Returns 1 if prime, 0 if not prime
int is_prime(int v)
{
for(int i = 2; i < v; i++) {
if(v % i == 0) {
return 0;
}
}
return 1;
}
// Thread routine
// calls is_prime to check if the input argument is prime
// Modifies the input parameter by dereferencing the pointer
//
// NOTE: that parameters and return value are pointers
void* thread_routine(void* args)
{
int* val = (int*)args;
if(is_prime(*val)) {
printf("THREAD %lu FOUND that %d is prime %p\n", pthread_self(), *val, val);
*val = 1;
} else {
printf("THREAD %lu FOUND that %d is not prime %p\n", pthread_self(), *val, val);
*val = 0;
}
return NULL;
}
int main()
{
int val = 0;
// Create 10 threads
pthread_t thr[10];
for(int i = 0; i < 10; i++) {
// NOTE: there is a single memory location for val which is passed to all threads
val = i + 2;
if(pthread_create(&thr[i], NULL, thread_routine, (void*)&val) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
}
// Wait for threads to finish
for(int i = 0; i < 10; i++) {
pthread_join(thr[i], NULL);
}
// Return success
return 0;
}

View File

@@ -0,0 +1,46 @@
/*
* pthreads_race.c - Shows a "race condition" when multiple threads
* try to race to modify a global value
* Due to unpredictable behavior in context switching
* the value of global_value does not result in what is
* expected
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int global_value = 0;
void* thread_routine()
{
for(int i = 0; i < 100000000; i++) {
global_value++;
}
return NULL;
}
int main()
{
// Create 5 threads
pthread_t thr_id[5];
for(int i = 0; i < 5; i++) {
if(pthread_create(&thr_id[i], NULL, thread_routine, NULL) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
}
// Wait for all threads to finish
for(int i = 0; i < 5; i++) {
pthread_join(thr_id[i], NULL);
}
// Print out final value of global value
// 5 threads * 100000000 iterations - expected value is 500000000
printf("PARENT READS GLOBAL: %d\n", global_value);
// Return success
return 0;
}

View File

@@ -0,0 +1,46 @@
/*
* pthreads_race_atomic.c - Uses an atomic add instruction to prevent
* the race condition that can happen when
* multiple threads modify a global value at the
* same time.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdatomic.h>
atomic_int global_value = 0;
void* thread_routine()
{
for(int i = 0; i < 100000000; i++) {
atomic_fetch_add(&global_value, 1);
}
return NULL;
}
int main()
{
// Create 5 threads
pthread_t thr_id[5];
for(int i = 0; i < 5; i++) {
if(pthread_create(&thr_id[i], NULL, thread_routine, NULL) == -1) {
printf("COULD NOT CREATE A THREAD\n");
exit(EXIT_FAILURE);
}
}
// Wait for all threads to finish
for(int i = 0; i < 5; i++) {
pthread_join(thr_id[i], NULL);
}
// Print out final value of global value
// 5 threads * 100000000 iterations - expected value is 500000000
printf("PARENT READS GLOBAL: %d\n", global_value);
// Return success
return 0;
}