According the this, unique_lock
can be used for recursive locking by declaring a std::unique_lock<std::recursive_mutex>
, and in fact that compiles fine.
However, it appears from examining the code (gcc 4.8.2 and 4.9.0) that unique_lock
doesn't defer to _Mutex.lock
, but rather implements the lock method itself:
void
lock()
{
if (!_M_device)
__throw_system_error(int(errc::operation_not_permitted));
else if (_M_owns)
__throw_system_error(int(errc::resource_deadlock_would_occur));
else
{
_M_device->lock();
_M_owns = true;
}
Clearly, this prevents recursive locking of the mutex, and in fact attempting to recursively lock throws the resource_deadlock_would_occur
exception.
Am I missing something here, is this a bug, or is the documentation for unique_lock just wrong?
TIA!!!
The std::scoped_lock and std::unique_lock objects automate some aspects of locking, because they are capable of automatically unlocking.
unique_lock<muType> is a wrapper allowing deferred locking, time-constrained attempts at locking, recursive locking, transfer of lock ownership, and use with condition variables.
A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked. On construction (or by move-assigning to it), the object acquires a mutex object, for whose locking and unlocking operations becomes responsible. The object supports both states: locked and unlocked.
std::recursive_mutex A calling thread owns a recursive_mutex for a period of time that starts when it successfully calls either lock or try_lock . During this period, the thread may make additional calls to lock or try_lock . The period of ownership ends when the thread makes a matching number of calls to unlock .
A common mistake is to confuse the mutex
with the lock
. A mutex
is an object that can be shared among threads (otherwise it would be useless). A lock however is not itself a thread-safe object. It should not be shared among threads. It is typically a local object on a stack. For example:
void foo()
{
std::unique_lock<std::mutex> lk(mut); // mut comes from some other scope
// mut locked here
// ...
} // mut unlocked here
In the example above, if foo()
is called recursively, you have undefined behavior because you will lock mut
recursively. On each recursion, you get a new unique_lock
though. So the unique_lock
is not aware of the recursion. If you really need to call foo()
recursively, you need to use a recursive mutex, for example:
void foo()
{
std::unique_lock<std::recursive_mutex> lk(mut); // mut comes from some other scope
// mut locked here
// ...
} // mut unlocked here
So: Yes, you can use std::unique_lock<std::recursive_mutex>
, and yes, your implementation is correct.
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