Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Try catch with locks in C++

In Java:

Lock lock = new ReentrantLock(); try{   lock.lock();   someFunctionLikelyToCauseAnException(); } catch(e){...} finally {   lock.unlock(); } 

My question is with this above example we know that the lock WILL always get unlocked because finally always executes, but what is the guarantee with C++?

mutex m; m.lock(); someFunctionLikelyToCauseAnException(); /// ???? 

How will this work and why?

like image 564
Brijendar Bakchodia Avatar asked Sep 06 '18 14:09

Brijendar Bakchodia


People also ask

What does try_ lock do?

std::try_lockAttempts to lock all the objects passed as arguments using their try_lock member functions (non-blocking).

What is mutex trylock?

mutex::try_lockTries to lock the mutex. Returns immediately. On successful lock acquisition returns true, otherwise returns false. This function is allowed to fail spuriously and return false even if the mutex is not currently locked by any other thread.

Is try catch good practice C++?

No. This is not good programming practice in C++ or in any other language.


2 Answers

For this we use the RAII-style construct std::lock_guard. When you use

std::mutex m; { // start of some scope     std::lock_guard lg(m);     // stuff } // end of scope 

lg will ensure that m will be unlocked no matter what path the scope is left as it is destroyed at scope exit and std::lock_guards destructor will call unlock

Even if an exception is thrown the stack will be unwound (stack unwinding) and that process destroys lg which in turn will call unlock guaranteeing that the lock is released.

like image 84
NathanOliver Avatar answered Sep 20 '22 22:09

NathanOliver


what is the guarantee with C++?

The relevant guarantee in C++ works a bit differently in comparison to the one you mention in Java. Instead of a finally block, it's relying on the destruction of automatic variables that happens upon the scope's exit, as the stack frame gets unwound. This stack unwinding occurs regardless of how the scope was exited, whether gracefully or due to an exception.

The preferred approach for the scenario concerning such locks is to use RAII, as implemented for example by std::lock_guard. It holds a mutex object passed to its constructor -- inside of which it calls the mutex's lock() method, after which the thread owns the mutex -- and upon stack unwinding at the scope's exit its destructor is called -- inside of which it calls the mutex's unlock() method, thus releasing it.

The code will look like this:

std::mutex m; {     std::lock_guard lock(m);     // Everything here is mutex-protected. } // Here you are guaranteed the std::mutex is released. 
like image 25
Geezer Avatar answered Sep 17 '22 22:09

Geezer