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?
std::try_lockAttempts to lock all the objects passed as arguments using their try_lock member functions (non-blocking).
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.
No. This is not good programming practice in C++ or in any other language.
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_guard
s 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With