views:

521

answers:

4

I'm working on win 32 multithreading with c++. Scenario: I have a function used by multiple threads. This function as a critical sections (or any kind of construct that can lock a resource). In the critical section an exception is thrown. At this point I need to take care of unlocking the resource in the exception catch block.

Is there any other way that this can be done? I mean, let's say that I don't want to have to remember to release the lock in the catch block, is there any common way to handle this problem to avoid this error prone scenario?

+3  A: 

Write a bracket class that takes a critical section as a constructor parameter. Call EnterCriticalSection in constructor and LeaveCriticalSection in destructor. Stack unwinding will do the rest if a C++ exception is thrown.

sharptooth
This is the behavior of the boost::mutex::lock object.
greyfade
scoped_lock rather.
greyfade
+15  A: 

The idea is to encapsulate the act of acquiring and releasing the critical section in an object such that constructing the object acquires the CS and destroying the object releases it.

struct CSHolder {
    explicit CSHolder(CRITICAL_SECTION& cs): lock(cs) {
        ::EnterCriticalSection(&lock);
    }
    ~CSHolder() { ::LeaveCriticalSection(&lock); }
    CRITICAL_SECTION& lock;
};


CRITICAL_SECTION gLock;
void foo() {
    CSHolder lockIt(gLock);
    // lock is held until lockIt is destroyed
}

The concept is called RAII - Resource Acquisition is Initialization. It is a very common idiom in modern C++.

D.Shawley
+2  A: 

If it is possible for you to use MFC then you can use CSingleLock to do this. You can use it like this:

void f()
{
  try
  {
    CSingleLock lock(&m_criticalSection, TRUE);

  }
  catch(/*some exception*/)
}

The lock will take care of unlocking the critical section in its destructor. Since lock, is a local object when the exception is thrown stack unwinds and the lock objects destructor is executed unlocking your critical section.

Naveen
+3  A: 

If you're using an existing framework, you likely already have an RAII container class that can do this for you. If you're using MFC, take a look at CSingleLock, if you're using boost look at scoped_lock.

It's a shame that everyone seems to have to (or think they have to) roll their own.

Michael Burr
I agree... it's also a shame that people are still using CRITICAL_SECTION directly instead of using boost::mutex or something similar. Maybe the correct answer is to write an adapter that implements the boost Lockable concept over a native CS.. hmmm...
D.Shawley