How to leave a critical section correctly?

I have the following C ++ code where I use the Critical Section object :

EnterCriticalSection(&cs); // code that may throw an exception LeaveCriticalSection(&cs); 

How can I guarantee that the LeaveCriticalSection function LeaveCriticalSection called even if an exception is thrown?

+6
source share
5 answers

Just write a guard using the destructor to clear:

 struct Guard { CriticalSection& cs; Guard(CriticalSection& cs) : cs(cs) { EnterCriticalSection(cs); } ~Guard() { LeaveCriticalSection(cs); } Guard(const Guard&) = delete; Guard& operator = (const Guard&) = delete; }; 

Using:

 void f() { Guard guard(cs); ... } 
+8
source

Use IIIL (Initialization of the acquisition of resources):

 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 use MFC by accident, there are classes that abstract such things: Can Ccriticalsection be used in production?

+7
source

"How can I guarantee that the LeaveCriticalSection function is called even if an exception is thrown?"

You can write a small helper class as follows:

  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_; }; 

This ensures that the critical section is unlocked whenever (and why ever) the area remains.

+3
source

I suggest you not to use critical WinAPI partitions. You can get the same using std :: mutex . When you use it, you can also use the RAII idiom shell to automatically unlock the mutex ( std :: lock_guard ).

UPDATE: one difference between the critical sector and the mutex, which you can lock the critical section several times in one thread, but this is not true for simple std :: mutex. If you require recursive locking behavior, use std :: recursive_mutex std::lock_guard<std::recursive_mutex>

UPDATE 2: a detailed distinction between critical sections and mutexes is described here , performance comparison here .

Reasons: it is better to use the standard mechanism when you can. If you are using a platform-specific thing, wrap it around. Therefore, if you are afraid for performance, create a critical section class with lock / unlock methods (to meet the requirements of BasicLocakable ) and use std::lock_guard<MyCriticalSection> .

+3
source

Other answers are correct regarding the use of RAII objects, but I find it worth noting 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 
+1
source

Source: https://habr.com/ru/post/986355/


All Articles