I'm learning pthread and wait conditions. As far as I can tell a typical waiting thread is like this:
pthread_mutex_lock(&m);
while(!condition)
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
What I can't understand is why the line while(!condition)
is necessary even if I use pthread_cond_signal()
to wake up the thread.
I can understand that if I use pthread_cond_broadcast()
I need to test condition, because I wake up all waiting threads and one of them can make the condition false again before unlocking the mutex (and thus transferring execution to another waked up thread which should not execute at that point).
But if I use pthread_cond_signal()
I wake up just one thread so the condition must be true. So the code could look like this:
pthread_mutex_lock(&m);
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
I read something about spurious signals that may happen. Is this (and only this) the reason? Why should I have spurious singnals? Or there is something else I don't get?
I assume the signal code is like this:
pthread_mutex_lock(&m);
condition = true;
pthread_cond_signal(&cond); // Should wake up *one* thread
pthread_mutex_unlock(&m);
The real reason you should put pthread_cond_wait in a while loop is not because of spurious wakeup. Even if your condition variable did not have spurious wakeup, you would still need the loop to catch a common type of error. Why? Consider what can happen if multiple threads wait on the same condition:
Thread 1 Thread 2 Thread 3
check condition (fails)
(in cond_wait) unlock mutex
(in cond_wait) wait
lock mutex
set condition
signal condvar
unlock mutex
lock mutex
check condition (succeeds)
do stuff
unset condition
unlock mutex
(in cond_wait) wake up
(in cond_wait) lock mutex
<thread is awake, but condition
is unset>
The problem here is that the thread must release the mutex before waiting, potentially allowing another thread to 'steal' whatever that thread was waiting for. Unless it is guaranteed that only one thread can wait on that condition, it is incorrect to assume that the condition is valid when a thread wakes up.