Reputation: 10499
I have the following C++ code where I make use of the Critical Section object:
EnterCriticalSection(&cs);
// code that may throw an exception
LeaveCriticalSection(&cs);
How can I ensure that the LeaveCriticalSection
function is called even if an exception is thrown?
Upvotes: 8
Views: 2934
Reputation: 3022
The other answers are correct about using RAII objects but I feel it is worth pointing out an easy way to do this with Boost.ScopeExit
.
#include <boost/scope_exit.hpp>
...
EnterCriticalSection(&cs);
BOOST_SCOPE_EXIT(&cs) {
LeaveCriticalSection(&cs);
} BOOST_SCOPE_EXIT_END
// code that may throw an exception
Upvotes: 1
Reputation: 3825
I suggest you not to use WinAPI critical sections. You can get the same by using std::mutex. When you use it you also can use RAII idiom wrapper for auto unlocking mutex (std::lock_guard ).
UPDATE: one difference between critical section and mutex that you can lock critical section multiple times on one thread but this is not true for simple std::mutex. If you need recursive behaviour of locking use std::recursive_mutex std::lock_guard<std::recursive_mutex>
UPDATE 2: Detailed difference between critical sections and mutexes are described here, performance comparison is here.
Reasons: It is better to use standard-defined mechanism whenever you can. If you use platform-specific thing - wrap it around. So if you afraid for performance - create Critical section class with lock/unlock methods (to meet BasicLocakable concept requirements) and use std::lock_guard<MyCriticalSection>
.
Upvotes: 3
Reputation: 1
"How can I ensure that the LeaveCriticalSection function is called even if an exception is thrown?"
You can write a small helper class like this:
class CsLocker {
public:
CsLocker(CriticalSection& cs)
: cs_(cs) {
EnterCriticalSection(&cs_);
}
~CsLocker() {
LeaveCriticalSection(&cs);
}
CsLocker(const CsLocker&) = delete;
CsLocker& operator=(const CsLocker&) = delete;
private:
CriticalSection& cs_;
};
That will guarantee that the critical section is unlocked whenever (and why ever) the scope is left.
Upvotes: 4
Reputation: 50016
Use RAII (Resource Acquisition Is Initialization) idiom:
struct GuardCS {
GuardCS(CRITICAL_SECTION& p_cs) : cs(p_cs){
EnterCriticalSection(&cs);
}
~GuardCS() {
LeaveCriticalSection(&cs);
}
private:
// Protect against copying, remove: =delete on pre c++11 compilers
GuardCS(GuardCS const &) = delete;
GuardCS& operator =(GuardCS const &) = delete;
CRITICAL_SECTION& cs;
};
If you are using MFC by any chance there are classes that abstract such stuff: is Ccriticalsection usable in production?
Upvotes: 8
Reputation:
Just write a guard utilizing the destructor for clean up:
struct Guard {
CriticalSection& cs;
Guard(CriticalSection& cs)
: cs(cs)
{
EnterCriticalSection(cs);
}
~Guard() {
LeaveCriticalSection(cs);
}
Guard(const Guard&) = delete;
Guard& operator = (const Guard&) = delete;
};
Usage:
void f() {
Guard guard(cs);
...
}
Upvotes: 9