17

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

jotik
  • 17,044
  • 13
  • 58
  • 123
WallStProg
  • 391
  • 4
  • 8

1 Answers1

32

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.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • Thanks, Howard! That makes things much clearer. Prob. should have been obvious from reading the code, but the fact that unique_lock is intended to be allocated on the stack didn't jump out at me. – BillT Dec 29 '14 at 15:08
  • Excellent answer. The answer is simple and the concepts are simple, however it's quite easy to get things mixed up! – lmat - Reinstate Monica May 28 '18 at 03:53