Condition Variables

Condition variables are variables that represent certain conditions and can only be used in monitors. Associated with each condition variable, there is a queue of threads and two operations: condition signal and condition wait. When a thread calls condition wait, the caller is put into the queue of that condition variable. When a thread calls condition signal, if there are threads waiting in that condition variable's queue, one of them is released. Otherwise, the condition signal is lost.

There is a subtle problem, however. If condition variables can only be used in a monitor, a condition signal can only be performed within a monitor. If there are waiting threads, one of them will be released and as a result there are two threads executing within the monitor. One of them is the caller that triggers the release and the other is the one being released. While there are some details and different ways to prevent this from happening, for our purpose, we can assume only one of these two threads will be executing. It could be the caller or the one being released.

In our simulation example, a mutex lock is used to protect the monitor from having more than one threads in execution. This lock mechanism causes a little complication. More precisely, if a thread calls condition signal to release another thread and the released thread receives the control, then the monitor lock owned by the caller must be released and be given to the released thread. How could this exchange of lock be implemented?

Fortunately, all problems can be solved easily. Let us start with the declaration of a condition variable.

Declaration and Initialization

To declare a condition variable, use type cond_t. To initialize it, use function cond_init(). Note that all condition variable related names start with cond_.

#include  <synch.h>

cond_t  CondVar;

int  cond_init(
          cond_t  *CondVar, /* ptr to cond. var. */
          USYNC_THREAD,     /* use this in CS270 */
          (void *) NULL);   /* always use this   */

Blocks on a Condition Variable

A thread can call function cond_wait() to block itself until the event represented by that condition variable occurs.

#include  <synch.h>

cond_t  CondVar;

int  cond_wait(
          cond_t  *CondVar, /* ptr to cond. var. */
          mutex_t *Mutex);  /* assoc. mutex ptr  */
The following is a typical use of a conditional variable within a monitor. MonitorLock is a mutex lock for locking the monitor and CondVar is a condition variable.
#include  <synch.h>

mutex_t   MonitorLock;
cond_t    CondVar;

mutex_lock(&MonitorLock);
     while (!cond)
          cond_wait(&CondVar, &MonitorLock);
mutex_unlock(&MonitorLock);

Signals a Condition Variable

To signal a condition variable, use cond_signal():

#include  <synch.h>

cond_t  CondVar;

int  cond_signal(
          cond_t  *CondVar); /* ptr to cond. var. */

The following is a typical use of cond_wait() and cond_signal():

#include  <synch.h>

mutex_t   MonitorLock;
cond_t    CondVar;

mutex_lock(&MonitorLock);
     while (!cond)
          cond_wait(&CondVar, &MonitorLock);
mutex_unlock(&MonitorLock);

mutex_lock(&MonitorLock);
     if (cond)
          cond_signal(&CondVar);
mutex_unlock(&MonitorLock);

We have discussed the cond_wait() part. Since threads are continually testing a variable to know if a condition is met, some thread who takes the responsibility to signal a condition variable must set the condition to indicate that the condition occurs. In the above, if condition cond is met, a thread calls cond_signal(). Thus, one thread waiting on that condition is awakened, retests the condition, and perhaps continues.