Managing critical sections using scope in C++

September 4, 2010

Mutexs are a great way to manage multi-threaded applications. It makes sure that two threads can’t change something while it’s being used somewhere else.

The only drawback to using them is that you must unlock them when you’ve finished with the critical section of code. You can forget to unlock it, miss putting an unlock in a code path, or an exception can divert around your carefully crafted code.

A simple trick can make your life as a programmer easier. In C++ you can use scoping to define a critical section and it will manage your mutex for you.

Here’s a simple example class that mimics a Mutex:

class Mutex
{
public:
 Mutex() : state(false)
 {
 }
 void lock()
 {
 state = true;
 std::cout << "locked\n";
 }
 void unlock()
 {
 state = false;
 std::cout << "unlocked\n";
 }
 bool state;
};

I’ve added string output so you can see when the lock and unlock methods are called. The standard way to use it would be something like this:


TestMutex.lock();
 // do something
 TestMutex.unlock();

Let’s create a new class to manage the mutex for us using scoping:


class Access
{
public:
 Access( Mutex& singleton ) : m(singleton)
 {
 m.lock();
 }
 ~Access()
 {
 m.unlock();
 }
 Mutex& m;
};

The constructor of the Access class saves a reference to a mutex and locks the mutex. When the destructor is called the mutex is unlocked.

How do we use this?

  • Create a block that surrounds your critical section that you want to protect with a mutex
  • Instantiate an object of the Access class FIRST.

Here’s an example:


{
 Access a(TestMutex);
 std::cout << "Test 1\n";
 }

If you run this you’ll get this:


locked
 Test 1
 unlocked

It locks the mutex before the work is done and as soon as the program exits the block it calls the destructor of the Access and unlocks the mutex. It’s simple and makes it impossible to forget to unlock the mutex.

Hope you find this useful. In the next post I’ll show you how this protects you from failing to unlock your mutex if you get exceptions.