Skip to content

Instantly share code, notes, and snippets.

@rtv
Created February 19, 2013 19:56
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save rtv/4989304 to your computer and use it in GitHub Desktop.
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.
#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;
}
@paul-cybercitizen
Copy link

Is the below message correct? I thought I read that threads can wake from a waiting on a condition for spurious reasons, so we can't assume a signal was received when waking

puts( "[thread main] wake - cond was signalled." );

@paul-cybercitizen
Copy link

Is the below message correct? I thought I read that threads can wake from a waiting on a condition for spurious reasons, so we can't assume a signal was received when waking

puts( "[thread main] wake - cond was signalled." );

The other thread signals before releasing the lock, maybe that guarantees to the waked thread that the signal was received?

@rtv
Copy link
Author

rtv commented Jun 9, 2020

@rtv
Copy link
Author

rtv commented Jun 9, 2020

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