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 pthread_cond_wait() function blocks the calling thread, waiting for the condition specified by cond to be signaled or broadcast to. When pthread_cond_wait() is called, the calling thread must have mutex locked.
Therefore, if the condition is already satisfied before the worker thread reaches the while loop then there is no need to enter the while loop and run pthread_cond_wait at all. Remember that you're in a multi-threaded environment, meaning the order of what happens can vary in an unpredictable way.
The pthread_cond_signal() function wakes up at least one thread that is currently waiting on the condition variable specified by cond. If no threads are currently blocked on the condition variable, this call has no effect.
Yes, pthread_cond_wait , when successful, causes the thread to wait until notified.
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.
Suppose you don't check the condition. Then usually you can't avoid the following bad thing happening (at least, you can't avoid it in one line of code):
Sender Receiver locks mutex sets condition signals condvar, but nothing is waiting so has no effect releases mutex locks mutex waits. Forever.
Of course your second code example could avoid this by doing:
pthread_mutex_lock(&m); if (!condition) pthread_cond_wait(&cond, &m); // Thread stuff here pthread_mutex_unlock(&m);
Then it would certainly be the case that if there is only ever at most one receiver, and if cond_signal
were the only thing that could wake it up, then it would only ever wake up when the condition was set and hence would not need a loop. nos covers why the second "if" isn't true.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With