Conditional variables are useful in cases where you want a thread to wait for something that happens in another thread. For instance, in a producer/consumer scenario with one or or more producing threads and one consuming thread, conditional variables can be used to signal the consuming thread that new data is available.
A wait on a conditional variable (queueCond in the producer/consumer example) is always coupled to a mutex (the queueMutex in the producer/consumer example), and should always be coupled to a "normal" state variable also (queue.empty() in the producer/consumer example). When used correctly, this ensures that no new data is missed in the consumer.
In general, the process should be:
whileloop on the state variable, looping as long as the data is not ready
whileloop, do a wait on the condition variable with
whileloop exits, we are now sure that new data is ready, and that the mutex is locked
With this scheme, no matter when the signalling and waiting threads are scheduled, the waiting thread will never miss data (as in, it will never be stuck waiting forever with valid data ready). This can be realized by manually trying to run through the steps for the signalling thread, recording the states of the mutex, condition and state variables, for each of the steps in the waiting thread.
pthread_cond_wait and the mutex
To facilitate the above process, it is required to call
pthread_cond_wait() with the mutex locked. When called,
pthread_cond_wait() will then unlock the mutex before putting the thread to sleep, and, just before returning for whatever reason, the mutex will be relocked. This also means that if some other thread currently has the mutex locked,
pthread_cond_wait() will wait for the mutex to be unlocked, and until the waiting thread can actually acquire the mutex - it will contend on it together with any other threads trying to lock the mutex at the same time.
Also, it may seem as if the
while loop waiting on the state variable could be substituted for a simple
if statement. However, the
while loop is needed, as the Posix standard allows
pthread_cond_wait() to do so-called "spurious" wakeups during the wait, without actually being signalled. Thus, the code needs to recheck the state variable to see if
pthread_cond_wait() returned due to actually being signalled, or due to one of these spurious wakeups.