Can unique_lock be used with a recursive_mutex?

9.1k views Asked by At

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

1

There are 1 answers

2
Howard Hinnant On

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.