Search code examples
c++multithreadingstlrecursive-mutex

Access the owners counter used by std::recursive_mutex


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?


Solution

  • 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