Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can unique_lock be used with a recursive_mutex?

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!!!

like image 629
WallStProg Avatar asked Dec 23 '14 18:12

WallStProg


People also ask

Does unique_lock automatically unlock?

The std::scoped_lock and std::unique_lock objects automate some aspects of locking, because they are capable of automatically unlocking.

What is unique_lock?

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.

How does a unique lock work?

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.

Is std :: mutex recursive?

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 .


1 Answers

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.

like image 192
Howard Hinnant Avatar answered Oct 05 '22 12:10

Howard Hinnant