Recommended

Multicore community

 

Articles

Intel.com

Microsoft.co.il

 

Community

Microsoft Forums

Intel's Forum

Intel's Multicore Community

 

Resources

http://msdn.com/concurrency

Intel Multicore

NVidia Multicore GPU

 

Downloads

.Net Parallel Extensions

Intel's TBB

WinModules   

 

Tools

AsyncOp Logger

Intel thread analysis

Intel VTune

 

Contact

Asaf Shelly

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ichilov

-->

 

 

 

 

 

 
2 / 1
 
 
 
 
 
 
 

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.