Conditional Variables

 

                              Conditional Variables

conditional variable in operating system programming is a special kind of variable that is used to determine if a certain condition has been met or not. It is used to communicate between threads when certain conditions become true.

A conditional variable is like a queue. A thread stops its execution and enters the queue if the specified condition is not met. Once another thread makes that condition true, it sends a signal to the leading thread in the queue to continue its execution.

If there is no thread in the queue, the signal is wasted.

Supported actions

There are two types of actions that can be performed with condition variables:

  • wait
  • signal

We use the wait instruction in a thread if we want to halt the execution of that thread till a certain condition is met.

We use the signal instruction if we want to continue executing the leading thread in the waiting queue.

Difference between a conditional variable and a semaphore

Often semaphore is confused with the conditional variable. Some of the differences between a semaphore and a conditional variable are listed in the table below:

The thread waits till a certain condition is met.

Only those threads wait which make the value of the semaphore less than or equal to 0.

The signal() is wasted if there is no thread waiting.

The sem_post() is not wasted even if no thread is waiting. The value of the semaphore is increased.

We can run all waiting threads using broadcast unlocking.

We can not run all waiting threads using broadcast unlocking.

The wait() function almost always block its caller.

The wait() function does not always block its caller.

It is mostly used with mutex. It signals the change in state from one thread to another.

It is mostly used to solve critical section problems.

Example

There are different methods to create conditional variables. We will consider an example written using the pthread conditional variables.

The following snippet of code has been taken from the book “Operating Systems: Three Easy Pieces”:

In the above snippet of code, we want to implement the threads such that the parent thread waits for the child thread to change the status of the variable done.

The program begins by creating a new thread in line 29. In the newly created thread, the child function is executed. Inside the child function, the thr_exitfunction is called.

In the thr_exit function, the thread first acquires the control of the mutex lock named m. This ensures that the execution of this function is not interrupted by the parent thread under any circumstances. After it acquires the lock, it changes the status of the variable done, runs the signal instruction for the conditional variable in line 8, and unlocks the mutex.

On the other hand, the parent thread runs the thr_join function. In the thr_join function, the thread first acquires the control of the mutex and enters the waiting queue after executing line 21.

If the parent thread runs first, it will enter the queue and start waiting for the signal by the child thread.

If the child thread runs first, it will change the status of the done variable, and the parent thread will never execute the wait instruction.

Hence, the functionality of the code remains intact.