7

Is there a way to tell whether or not the current thread in C++11 holds a lock on a mutex? In particular I want to ensure that certain functions in a class are only called while the calling thread holds onto a lock (via std::lock_guard, std::unique_lock, or something similar) for the object, with the std::mutex being a member variable.

To avoid repeated locking and unlocking while the object is being used extensively, the responsibility for locking the mutex needs to be up to the caller, and cannot be in each individual function, and if the current thread does not have a lock on the mutex when any of these functions are called, I want to throw an exception.

It seems that I can't just use std::try_lock followed by an unlock as necessary because std::try_lock's behavior is undefined if the current thread already holds the lock.

markt1964
  • 2,638
  • 2
  • 22
  • 54
  • *"It seems that I can't just use `std::try_lock` followed by an `unlock` as necessary because `std::try_lock`'s behavior is undefined if the current thread already holds the lock."* - not if you switch to [`recursive_mutex`](http://en.cppreference.com/w/cpp/thread/recursive_mutex). If you're using pthreads, `PTHREAD_MUTEX_ERRORCHECK` is another option - if you don't get an error, `throw`. – Tony Delroy Mar 03 '15 at 07:07

2 Answers2

6

The way I would recommend doing this is to have the functions that can only be called while holding the mutex take a reference to a std::unique_lock or std::lock_guard. In the case of unique_lock you probably also want to assert that it actually holds the lock.

This will leverage the compiler to enforce your requirements.

Presumably these functions are internal / private to your class, and you have user-facing functions that acquire the lock and then call these ones. If so, having an additional argument won't pollute the user facing API.

Something along these lines:

// public
void A::public_function() {
   std::lock_guard<std::mutex> l(m_mutex);
   // ... do stuff
   b(l);
   // ... do more stuff
}

// private
void A::b(std::lock_guard const& l) {
   // ... do stuff that requires holding the mutex
}

If you need to use unique_lock instead, simply assert that l.owns_lock() is true in your function (in case you want to throw an exception).

My experience with recursive mutexes is that they make it easy to not take your lock strategy and ownership as serious as it deserves. And that they can end up biting you later. See this post.

Arvid
  • 10,915
  • 1
  • 32
  • 40
  • I do not (completely) agree with the last statement. Yes, blindly using a recursive mutex to make things easy is a bad thing. But if you start from a well-thought of lock strategy and recursive mutexes are the best fit, then you should just use them. Your solution just pollutes your function APIs (even if it's just internal). – KillianDS Mar 05 '15 at 08:48
1

Just use a recursive mutex and lock/unlock in your code as you would do without the guarantee of an upper-level lock. Then provide that mutex also to the calling code who can use it (or not).

Most importantly, if the upper layer does not lock, your code will still work perfectly, though maybe at a degraded speed. If the upper layer does lock, this will be not much more than a check if it owns the lock and an refcount increment/decrement, similar overhead to what you were planning to do anyway.

There is (currently) no interface defined in the C++ standard library that allows you to check if the mutex is locked and you are the owner.

KillianDS
  • 16,936
  • 4
  • 61
  • 70
  • Thank. More information for readers (recursive mutex can be suitable in some cases) : https://stackoverflow.com/questions/2415082/when-to-use-recursive-mutex – cppBeginner Feb 14 '18 at 11:45