Condition Variables
Condition Variables are common in versions of the UNIX
operating system. Microsoft introduced support for Condition Variables with
Windows Vista. On Windows OS the synchronization object is interprocess and
therefore does not have a name and cannot be shared between processes.
The synchronization object Condition Variable is a
composition of an Event and a Locking object (Critical Section in Windows). Here
is a simple scenario that explains the motivation for using a Condition
Variable:
A server application has several threads handling incoming
events. This is a web server and it has a socket that owns port 80 of the
computer. All clients connect to this port to send requests. The server finds
the first thread that is waiting and wakes it up to read the buffer from the
socket. The thread reads the buffer, handles the request and then goes back to
the socket to send the response. [I can tell you that this is not a best
practice but it demonstrates the need]
In the scenario above all worker threads wait on an event
that the server signals. When the worker thread wakes up is must lock the socket
before it can do anything. The worker thread will handle the event and then
unlock and go back to wait for another event signal. The server has a main
thread that waits on the socket and whenever there is data it wakes up a worker
thread by signaling the event. This main thread is waiting on multiple
synchronization objects and has other tasks to perform with many worker threads.
A worker thread that started handling the socket Event is the owner of the Event
object and must clear it when it is done to notify the system that another
socket event can be handled. The worker thread that owns the event is the only
one that can clear it because it is the only one that knows that no one else is
using it.
See the following pseudo code:
Wait on Event
Lock
Work
Clear Event
Unlock
This code will generate the following work flow:
Wait on Event
Lock
Work
Clear Event
Unlock
[1]
Wait on Event
Lock
Work
Clear Event
Unlock
There is a small window between the time that the worker
thread cleared the event to notify the system that more jobs can be handles, and
the time that the thread went back to wait on the event.
If the Event is a Pulse Event (gray
part above left out) then the thread that Pulses the event does this after the
lock is released. The wait for event in the scenario above comes after the
unlock. This is the window (marked in red above).
During this exposure window the main thread might Pulse the Event and this
particular worker thread could miss the pulse.
If the Event is not a Pulse event and therefore has to be
cleared, we make sure that only one thread does the job by using the lock. The
problem is that it is possible that more than one thread see the event and then
only one will receive the ownership over the lock while all the rest block on
the lock object and do nothing.
It is possible to manage parallelism without Condition
Variables but it is easier to manage the execution flow with them. Condition
Variables are commonly used with Seqlock - Sequential Lock AKA Reader / Writer
lock.
The idea behind Condition Variables is the following
sequence:
1) Wait on Event
2) Lock and Continue execution
3) ....... do some work ....
4) Unlock and Wait on Event
2) Lock and Continue execution
3) ....... do some work ....
4) Unlock and Wait on Event
2) Lock and Continue execution
3) ....... do some work ....
This way the window of exposure that we have seen above is
eliminated. The thread starts with waiting on the event. In an atomic operation
the thread resumes and locks the Lock object. Then the thread does its work and
when it is done it performs an atomic operation that unlocks and enters another
wait state on the event.
Library support for Condition Variables include a higher
level behavior relatively to Event objects and include Wake One thread and Wake
All threads. This is in a way similar to an Event that releases all waiting
threads vs. one that release only one waiting thread. Condition Variables are
managed better than Events in this aspect.