Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a while loop needed around pthread wait conditions?

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); 
like image 207
Emiliano Avatar asked Jul 16 '09 09:07

Emiliano


People also ask

What does Pthread cond wait do?

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.

Does pthread_cond_wait need to be in a while loop?

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.

What is Pthread_cond_signal?

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.

Is pthread_cond_wait busy waiting?

Yes, pthread_cond_wait , when successful, causes the thread to wait until notified.


2 Answers

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.

like image 77
Chris Lu Avatar answered Sep 20 '22 14:09

Chris Lu


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.

like image 24
Steve Jessop Avatar answered Sep 16 '22 14:09

Steve Jessop