/******************************************************************** This is a sample threaded program in C that uses mutexes and condition variables. The main thread creates 4 threads. Each thread increases a counter by one, if (the current value of the counter) mod (the number of threads) is equal to the thread's id. This results in thread 0 printing 0,4,8,..., 1 printing 1,5,9,... etc. The counter is increased by the thread which's turn it is to print. Notice that I have set the thread attributes to joinable. Compilation: gcc threads-synchro.c -o threads-synchro -Wall -lpthread ********************************************************************/ #include #include #include #define NUM_THREADS 4 #define NUM_REPEAT 10 /* these are the parameters of a the thread */ struct ThreadParams { /* the id of the thread */ int id; /* condition variable and mutex to ensure thread id is safely read and written by threads */ pthread_cond_t *idCond; pthread_mutex_t *idMutex; /* the number of repetitions completed */ int repetitions; /* mutex for synchronization - this would actually be easier with one more condition variable, it only serves as mutex illustration */ pthread_mutex_t *repetMutex; }; /* This will be the main for each created thread. */ void * thread_function (void *arg) { /* arg is actually a ThreadParams*. It is given as a void* (which means "pointer to anything") just because the threads library requires that. */ struct ThreadParams *params = (struct ThreadParams*) arg; int id, localRepetitions = 0; /* CAREFULLY read the id parameter */ pthread_mutex_lock(params->idMutex); id = params->id; /* change params->id to signal that main thread does not need to wait any more */ params->id = NUM_THREADS; /* wake the main() thread (allow it to further update params->id) */ pthread_cond_signal(params->idCond); pthread_mutex_unlock(params->idMutex); /* Notice that we need to copy repetitions to a local variable to avoid locking the mutex during the entire while loop. */ while (localRepetitions < NUM_REPEAT) { /* CAREFULLY read the repetitions parameter */ pthread_mutex_lock(params->repetMutex); localRepetitions = params->repetitions; if (localRepetitions < NUM_REPEAT && localRepetitions % NUM_THREADS == id) { /* It's this thread's turn to print! Print and increase repetitions counter. */ printf( "Thread %d, repetitions = %d\n", id,localRepetitions ); fflush(NULL); ++localRepetitions; params->repetitions = localRepetitions; /*sleep(2);*/ } /*sleep(2);*/ pthread_mutex_unlock(params->repetMutex); /*sleep(2);*/ } return NULL; } int main() { int i, status; struct ThreadParams arg; pthread_t thread[NUM_THREADS]; pthread_attr_t attr; /* condition variable and mutex to ensure thread id is safely read by threads */ pthread_cond_t idCondObj = PTHREAD_COND_INITIALIZER; pthread_mutex_t idMutexObj = PTHREAD_MUTEX_INITIALIZER; /* mutex for synchronization - this would actually be easier with a condition variable, it only serves as mutex illustration */ pthread_mutex_t repetMutexObj = PTHREAD_MUTEX_INITIALIZER; /* initialize and set the thread attributes */ pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); /** initialize the condition variable and mutexes */ pthread_cond_init(&idCondObj,NULL); pthread_mutex_init(&idMutexObj,NULL); pthread_mutex_init(&repetMutexObj,NULL); /* initialize the arguments object */ arg.id = 0; arg.idCond = &idCondObj; arg.idMutex = &idMutexObj; arg.repetitions = 0; arg.repetMutex = &repetMutexObj; /* creating threads */ for ( i=0; i0 && arg.id < NUM_THREADS) { /* Wait until the previously created thread reads its id. We use while (instead of if i>0 ...) to avoid spurious wakeups. */ pthread_cond_wait(arg.idCond, arg.idMutex); } arg.id = i; pthread_mutex_unlock(arg.idMutex); /* create the new thread */ status = pthread_create (&thread[i], &attr, thread_function, &arg); if (status != 0) { fprintf(stderr,"Creating thread %d failed!",i); return 1; } } /* join threads (== wait until all the other threads exit) */ for ( i=0; i