7

I have a case where my algorithm's decisions are based on the depth of a shared std::recursive_mutex.

#include <iostream>
#include <mutex>
#include <thread>

int g_i = 0;
std::recursive_mutex g_i_mutex;

void bar() {
  std::lock_guard<std::recursive_mutex> lock(g_i_mutex);
  switch (get_counter(g_i_mutex)) { // some way to find the number of owners
    case 1: std::cout << "depth 1\n"; break;
    case 2: std::cout << "depth 2\n"; break;
    default:;
  }
}

void foo() {
   std::lock_guard<std::recursive_mutex> lock(g_i_mutex);
   std::cout << "hello\n";
   bar();
}

int main() {
  foo(); //print hello then depth 2
  bar(); //print depth 1
}

I've read that recursive mutexes hold a use count of some sort, and they increase and decrease it with each call to lock/unlock, is there a way to access that information?

YSC
  • 38,212
  • 9
  • 96
  • 149
DsCpp
  • 2,259
  • 3
  • 18
  • 46
  • 1
    There probably will be a counter somewhere, but that is not part of [the interface](http://en.cppreference.com/w/cpp/thread/recursive_mutex). – Bo Persson Sep 26 '17 at 11:26
  • Not in portable way, you still have access to `std::recursive_mutex::native_handle()` which might have a richer interface for your implementation. – Jarod42 Sep 26 '17 at 11:27

1 Answers1

10

No you cannot.

This is impossible because the counter you mentioned is an implementation solution, it may or may not exist. If you knew a specific implementation of the Standard Library used a counter, you could use some magic (pointer arithmetic and casts) to get it, but that would be undefined behavior.

That being said, nothing forbids you to define your own recursive_mutex:

#include <iostream>
#include <mutex>
#include <atomic>

class recursive_mutex
{
    std::recursive_mutex _mutex;
    std::atomic<unsigned> _counter;
public:
    recursive_mutex() : _mutex(), _counter(0) {}
    recursive_mutex(recursive_mutex&) = delete;
    void operator=(recursive_mutex&) = delete;
    void lock() { _mutex.lock(); ++_counter; }
    bool try_lock() { bool result = _mutex.try_lock(); _counter += result; return result; }
    void unlock() { --_counter; _mutex.unlock(); }
    unsigned counter() { return _counter; }
};

int main() {
  recursive_mutex m;
  m.lock();
  m.lock();
  std::cout << m.counter() << "\n";
  m.unlock();
  std::cout << m.counter() << "\n";
  m.unlock();
}

2
1

demo

YSC
  • 38,212
  • 9
  • 96
  • 149
  • The reason why it can't be done just with recursive mutex, and an implementation example of how to do it. thanks a lot! – DsCpp Sep 26 '17 at 11:39
  • using this with guard_lock may result unwanted counter increase, because lock_guard calls lock, and not try_lock, right? – DsCpp Sep 26 '17 at 12:08
  • In a multi threaded scenario, when another thread will try to lock the mutex by creating a lock_guard object wouldn't the counter be increased, although the mutex won't get locked? (lock_guard tries to lock a mutex via lock, and not try_lock) – DsCpp Sep 26 '17 at 14:02
  • 1
    @DsCpp look: `_counter` is incresed only after `std::recursive_mutex::lock()` returned. If a lock guard fails to lock the mutex, it will block forever and never increase the counter ;) – YSC Sep 26 '17 at 14:04
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155341/discussion-between-dscpp-and-ysc). – DsCpp Sep 26 '17 at 14:10