Created
February 19, 2013 19:56
-
-
Save rtv/4989304 to your computer and use it in GitHub Desktop.
An example of using pthread's condition variables, showing how to block a main thread while waiting for worker threads to finish their work, without joining the threads. This could be useful if you want to loop the threads, for example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <pthread.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <assert.h> | |
/* Compile like this: | |
gcc --std=c99 -lpthread cond.c -o cond | |
*/ | |
const size_t NUMTHREADS = 20; | |
/* a global count of the number of threads finished working. It will | |
be protected by mutex and changes to it will be signalled to the | |
main thread via cond */ | |
int done = 0; | |
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; | |
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; | |
/* Note: error checking on pthread_X calls ommitted for clarity - you | |
should always check the return values in real code. */ | |
/* Note: passing the thread id via a void pointer is cheap and easy, | |
* but the code assumes pointers and long ints are the same size | |
* (probably 64bits), which is a little hacky. */ | |
void* ThreadEntry( void* id ) | |
{ | |
const int myid = (long)id; // force the pointer to be a 64bit integer | |
const int workloops = 5; | |
for( int i=0; i<workloops; i++ ) | |
{ | |
printf( "[thread %d] working (%d/%d)\n", myid, i, workloops ); | |
sleep(1); // simulate doing some costly work | |
} | |
// we're going to manipulate done and use the cond, so we need the mutex | |
pthread_mutex_lock( &mutex ); | |
// increase the count of threads that have finished their work. | |
done++; | |
printf( "[thread %d] done is now %d. Signalling cond.\n", myid, done ); | |
// wait up the main thread (if it is sleeping) to test the value of done | |
pthread_cond_signal( &cond ); | |
pthread_mutex_unlock( & mutex ); | |
return NULL; | |
} | |
int main( int argc, char** argv ) | |
{ | |
puts( "[thread main] starting" ); | |
pthread_t threads[NUMTHREADS]; | |
for( int t=0; t<NUMTHREADS; t++ ) | |
pthread_create( &threads[t], NULL, ThreadEntry, (void*)(long)t ); | |
// we're going to test "done" so we need the mutex for safety | |
pthread_mutex_lock( &mutex ); | |
// are the other threads still busy? | |
while( done < NUMTHREADS ) | |
{ | |
printf( "[thread main] done is %d which is < %d so waiting on cond\n", | |
done, (int)NUMTHREADS ); | |
/* block this thread until another thread signals cond. While | |
blocked, the mutex is released, then re-aquired before this | |
thread is woken up and the call returns. */ | |
pthread_cond_wait( & cond, & mutex ); | |
puts( "[thread main] wake - cond was signalled." ); | |
/* we go around the loop with the lock held */ | |
} | |
printf( "[thread main] done == %d so everyone is done\n", (int)NUMTHREADS ); | |
pthread_mutex_unlock( & mutex ); | |
return 0; | |
} |
Note that the condition is checked after cond returns. The worst that can happen is that the puts() is slightly misleading.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://en.wikipedia.org/wiki/Spurious_wakeup