#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex

std::recursive_mutex m1;
//std::mutex m1;

void thread1( int d )
{
    if ( d == 5 ) return;

    //std::unique_lock<std::recursive_mutex> my_lock( m1 ); // locked by default
    m1.lock();
    std::cout << "Depth " << d << " - got recursive_mutex!\n";
    thread1( d+1 );
    if ( d != 3 ) { // simulating one the threads failing to unlock. As a consequence m1.try_lock in main will fail
        m1.unlock();
    }
}

int main()
{
    std::thread t1( thread1, 0 );
    t1.join();
    // check mutex is unlocked
    if ( m1.try_lock() ) {
        std::cout << "Got m1 in main\n";
    } else {
        std::cout << "Could not get m1 in main\n";
    }
    return 0;
}
//Most of the time, if you think you want a recursive mutex, you probably need
//to change your design instead. A common use of recursive mutexes is where a
//class is designed to be accessible from multiple threads concurrently, so it
//has a mutex protecting the member data. Each public member function locks
//the mutex, does the work, and then unlocks the mutex. However, sometimes it’s
//desirable for one public member function to call another as part of its
//operation. In this case, the second member function will also try to lock the
//mutex, thus leading to undefined behavior. The quick-and-dirty solution is
//to change the mutex to a recursive mutex. This will allow the mutex lock in
//the second member function to succeed and the function to proceed.
//However, such usage is not recommended, because it can lead to sloppy
//thinking and bad design. In particular, the class invariants are typically
//broken while the lock is held, which means that the second member function
//needs to work even when called with the invariants broken. It’s usually
//better to extract a new private member function that’s called from both
//member functions, which does not lock the mutex (it expects it to already be
//locked). You can then think carefully about the circumstances under which
//that new function can be called and the state of the data under those
//circumstances.
//C++ Concurrency in Action
//Anthony Williams