#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; | |
} |
This comment has been minimized.
This comment has been minimized.
@KristupasSavickas the point of |
This comment has been minimized.
This comment has been minimized.
Should |
This comment has been minimized.
This comment has been minimized.
Sorry if I misunderstanding. Wouldn’t this deadlock if the main thread entered the loop before the workers finished? It looks like it holds the mutex lock during cond_wait. |
This comment has been minimized.
This comment has been minimized.
Aha I read it again I misunderstood! :) thanks for the example! |
This comment has been minimized.
This comment has been minimized.
@driskell, indeed it seems it would deadlock as u mentioned - what am I missing ? |
This comment has been minimized.
This comment has been minimized.
It seems will deadlock? |
This comment has been minimized.
This comment has been minimized.
@vineetgarc @js0701 |
This comment has been minimized.
This comment has been minimized.
Is it OK in this example to put |
This comment has been minimized.
This comment has been minimized.
No, bad things can happen if you call pthread_cond_signal() without holding the same mutex that waiting threads specifies in their pthread_cond_wait() call. If pthread_cond_signal() is called without holding the mutex, then the waiting thread can get into an infinite wait because the thread signalling the condition might do it in-between the waiting thread decides if it needs to wait and blocking in pthread_cond_wait(). The pthread_cond_signal() will only wake a waiting thread. If no thread was waiting, then the signal condition was lost and a thread that later starts to wait may wait forever. The above code doesn't suffer from this because inside the mutex-protected critical section, it checks the state of 'done' before deciding if it should wait. With 'done' less than NUMTHREADS, the waiting thread knows that at least one thread have still not signalled - so it's safe to wait on the condition variable. |
This comment has been minimized.
This comment has been minimized.
Zyxxel: If you use the same mutex before a pthread_cond_wait() call and pthread_cond_signal(), then they will be mutually exclusive, meaning you won't need to call pthread_cond_wait anyway, just use a flag. |
This comment has been minimized.
This comment has been minimized.
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." ); |
This comment has been minimized.
This comment has been minimized.
The other thread signals before releasing the lock, maybe that guarantees to the waked thread that the signal was received? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Note that the condition is checked after cond returns. The worst that can happen is that the puts() is slightly misleading. |
This comment has been minimized.
Nice example, but what's the point of keeping
done
global? Couldn't you keep it in the loop and increment it in the main loop when a condition occurs? You would need mutexes that way.