Introduction
With the release of Windows Vista, Microsoft introduced a new synchronization primitive called the "Condition Variable". In this article, I will explain (badly) the function of the Condition Variable and also provide a .NET wrapper.
Background
Thread synchronization can be a complex and sometimes frustrating task. I embrace anything which comes along and makes the task a little easier. Microsoft did just that, they introduced the Condition Variable. When I saw it, I said, "Awesome! can't wait to use it!". Unfortunately, the functionality is only exposed to the unmanaged world, and I work in a C# shop. So, what's a guy to do? Um.... Write a wrapper leveraging C++/CLI, expose the functionality to the .NET world, and write an article, of course!
Condition Variables Explained
So, what are condition variables anyway? Condition Variables allow a thread to release a lock (CRITICAL_SECTION
) and enter a wait state in a single atomic operation. Once the thread is awakened, it immediately requires the previously released lock. The waking of the thread is controlled via the CONDITION_VARIABLE
and associated Win32 API functions. For a far better explanation and a list of the Win32 API functions, see MSDN.
Using the Code
The first thing you will notice is that the C++ project contains not one, but two classes. Given that Microsoft does not expose the "Critical Section" functionality (they do, however, provide similar functionality via the System.Threading.Monitor
methods), I also had to write a wrapper for Critical Sections because Condition Variables require them.
You will also notice that I named the wrapper class for the "Condition Variable" functionality, "WaitCondition
", it just seems to fit the usage pattern better. Anyway, you have the code and can name it whatever you like. Below, you will find the basic pattern for using the classes (I've included a full port of a sample application from the "Using Condition Variables" section of the Vista/Server 2008 SDK):
WaitCondition waitCondition = new WaitCondition();
CriticalSection criticalSection = new CriticalSection();
criticalSection.Enter();
waitCondition.Sleep(criticalSection);
waitCondition.WakeOne();
DoSomething();
criticalSection.Exit();
waitCondition.Dispose();
criticalSection.Dispose();
Points of Interest
While it is technically okay to use the CriticalSection
class in place of the .NET System.Threading.Monitor
class, I would recommend against that. I tested this class against the Monitor
class, and it's about 60% slower. Unfortunately, there is no means by which to leverage the Monitor
class with Condition Variables.