Preamble
This is nothing earth-shattering, just a little trick I've picked up, and like because it is rather slick.
Introduction
In C# we use
lock, without a second thought, to prevent simultaneous access from multiple threads. However in plan vanilla C++, you need to explicitly
EnterCriticalSection and
LeaveCriticalSection. Sometimes you may enter, but forget to leave. This tip takes care of that, and makes the code more compact.
Usage
The code is used as shown below:
static Section mySection;
void SomeFunction()
{
{
Lock lock(mySection);
}
}
Simple, isn't it? Basically what you do is, define a
Section instance for each block of code that should be locked. This is usually a class member, but can easily be global too. Then wrap the portion of code to be locked in a block, and put a
Lock instance at the top of it, passing the
Section instance to it.
If you want several blocks that need to be locked from multiple threads, but not from each other, create the same number of
Sections and use them in each block.
Code
These are the contents of
lock.h, which contains the classes
Lock and
Section.
#pragma once
#include <windows.h>
class Lock;
class Section
{
CRITICAL_SECTION criticalSection;
public:
Section()
{
InitializeCriticalSection(&criticalSection);
}
~Section()
{
DeleteCriticalSection(&criticalSection);
}
private:
friend Lock;
void Enter() { EnterCriticalSection(&criticalSection); }
void Leave() { LeaveCriticalSection(&criticalSection); }
};
class Lock
{
Section & section;
public:
Lock(Section & s) : section(s) { section.Enter(); }
~Lock() { section.Leave(); }
};
That's it, quite simple (but see the disclaimer).
How it works
So what happens here? You veterans will find it quite obvious, but I'll explain it as easily as possible for others who don't.
First,
Section just hides a regular
CRITICAL_SECTION. Why hide it? Just to prevent unwary maintainers of our code from messing with it. The constructor and destructor initialize and delete the
CRITICAL_SECTION respectively.
The
Lock class does the actual locking. When we create an auto variable of this type in the code block, the constructor is called and enters the critical section defined in the
Section passed to it. Leaving the scope of the block calls the destructor, which in turn calls
LeaveCriticalSection.
Note that the
Section field in
Lock is a reference - this is to prevent the former's constructor from being called again, causing a double initialization of the same
CRITICAL_SECTION.
See Also
MSDN page for related APIs -
Critical Section Objects.
Disclaimer
This is just the bare-bones code to illustrate the principle, with no exception handling. You'll have to add that as needed. Sample compiled cleanly on Visual C++ 2010 Express, other versions may give warnings.