Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assert if a std::mutex is locked?

Tags:

c++

linux

gcc

c++11

With GCC 4.8.2 (on Linux/Debian/Sid 64 bits) -or GCC 4.9 when available - in C++11- I have some mutex

std::mutex gmtx; 

actually, it is a static member in some class Foo containing both alpha and beta methods below.

it is locked in alpha like

void alpha(void) {    std::lock_guard<std::mutex> g(gmtx);    beta(void);    // some other work } 

and I want to check in beta that indeed gmtx is locked:

void beta(void) {    assert (gmtx.is_locked());    // some real work } 

(notice that is_locked is only called inside assert... It can be very inefficient or even sometimes inaccurate)

Of course, I have other functions calling beta, e.g.

void gamma(void) {    std::lock_guard<std::mutex> g(gmtx);    beta();    // some other work } 

but is_locked does not exist.... How should I define it? (actually I would like to be sure that the mutex has been locked in the same thread by some [indirect] caller...)

(the reason I want to test that with assert is that beta could be called elsewhere)

I cannot use try_lock (unless using recursive mutexes), because in the common case it would lock an already locked mutex... (locked in the same thread by a caller) and this is not only undefined behavior but blocks entirely.

I want to avoid recursive mutexes (more costly than plain mutexes) unless I really have to.


NB: The real program is a bit more complex. Actually, all the methods are inside a class which maintain a naming bi-directional relation on "items". So I have inside that class a map from items to names and another from names to items. beta would be the internal method adding really a naming, and alpha and gamma would be the methods finding -or adding- an item by its name, or a name by its item.

PS: the real program is not yet released, but should become part of MELT - its future monitor; you can download it (alpha stage, very buggy) from here (a temporary location)

like image 965
Basile Starynkevitch Avatar asked Feb 19 '14 21:02

Basile Starynkevitch


People also ask

How do I know if mutex is locked?

If the mutex isn't currently locked by any thread, the calling thread locks it (from this point, and until its member unlock is called, the thread owns the mutex ). If the mutex is currently locked by another thread, the function fails and returns false , without blocking (the calling thread continues its execution).

What happens if you dont unlock the mutex?

If you don't, then a typical mutex is held in process memory and will simply cease to exist along with anything that might have access to it when the process terminates.

Are mutexes locks?

A Mutex is a lock that we set before using a shared resource and release after using it. When the lock is set, no other thread can access the locked region of code.


2 Answers

Strictly speaking, the question was about checking the lockedness of std::mutex directly. However, if encapsulating it in a new class is allowed, it's very easy to do so:

class mutex :     public std::mutex { public: #ifndef NDEBUG     void lock()     {         std::mutex::lock();         m_holder = std::this_thread::get_id();      } #endif // #ifndef NDEBUG  #ifndef NDEBUG     void unlock()     {         m_holder = std::thread::id();         std::mutex::unlock();     } #endif // #ifndef NDEBUG  #ifndef NDEBUG     /**     * @return true iff the mutex is locked by the caller of this method. */     bool locked_by_caller() const     {         return m_holder == std::this_thread::get_id();     } #endif // #ifndef NDEBUG  private: #ifndef NDEBUG     std::atomic<std::thread::id> m_holder; #endif // #ifndef NDEBUG }; 

Note the following:

  1. In release mode, this has zero overhead over std::mutex except possibly for construction/destruction (which is a non-issue for mutex objects).
  2. The m_holder member is only accessed between taking the mutex and releasing it. Thus the mutex itself serves as the mutex of m_holder. With very weak assumptions on the type std::thread::id, locked_by_caller will work correctly.
  3. Other STL components, e.g., std::lock_guard are templates, so they work well with this new class.
like image 109
Ami Tavory Avatar answered Sep 23 '22 06:09

Ami Tavory


std::unique_lock<L> has owns_lock member function (equivalent of is_locked as you say).

std::mutex gmtx; std::unique_lock<std::mutex> glock(gmtx, std::defer_lock);  void alpha(void) {    std::lock_guard<decltype(glock)> g(glock);    beta(void);    // some other work } void beta(void) {    assert(glock.owns_lock()); // or just assert(glock);    // some real work } 

EDIT: In this solution, all lock operations should be performed via unique_lock glock not 'raw' mutex gmtx. For example, alpha member function is rewritten with lock_guard<unique_lock<mutex>> (or simply lock_guard<decltype(glock)>).

like image 35
yohjp Avatar answered Sep 24 '22 06:09

yohjp