A non-recursive mutex cannot be locked more than once, even by the thread that holds the lock. This frequently becomes a problem if a program contains a number of functions, each of which must acquire a mutex, and you want to call one function as part of the implementation of another function:

{zcode:cpp}
IceUtil::Mutex _mutex;

void
f1()
{
    IceUtil::Mutex::Lock lock(_mutex);
    // ...
}

void
f2()
{
    IceUtil::Mutex::Lock lock(_mutex);
    // Some code here...

    // Call f1 as a helper function
    f1();                               // Deadlock!

    // More code here...
}
{zcode}

f1 and f2 each correctly lock the mutex before manipulating data but, as part of its implementation, f2 calls f1. At that point, the program deadlocks because f2 already holds the lock that f1 is trying to acquire. For this simple example, the problem is obvious. However, in complex systems with many functions that acquire and release locks, it can get very difficult to track down this kind of situation: the locking conventions are not manifest anywhere but in the source code and each caller must know which locks to acquire (or not to acquire) before calling a function. The resulting complexity can quickly get out of hand.

Ice provides a recursive mutex class RecMutex (defined in IceUtil/RecMutex.h) that avoids this problem:

{zcode:cpp}
namespace IceUtil {

    class RecMutex {
    public:
        RecMutex();
        RecMutex(MutexProtocol p);
        ~RecMutex();

        void lock() const;
        bool tryLock() const;
        void unlock() const;

        typedef LockT<RecMutex> Lock;
        typedef TryLockT<RecMutex> TryLock;
    };
}
{zcode}

Note that the signatures of the operations are the same as for IceUtil::Mutex. However, RecMutex implements a recursive mutex:

As for non-recursive mutexes, you must adhere to a few simple rules for recursive mutexes:

Using recursive mutexes, the code fragment shown earlier works correctly:

{zcode:cpp}
#include <IceUtil/RecMutex.h>
// ...

IceUtil::RecMutex _mutex;       // Recursive mutex

void
f1()
{
    IceUtil::RecMutex::Lock lock(_mutex);
    // ...
}

void
f2()
{
    IceUtil::RecMutex::Lock lock(_mutex);
    // Some code here...

    // Call f1 as a helper function
    f1();                               // Fine

    // More code here...
}
{zcode}

Note that the type of the mutex is now RecMutex instead of Mutex, and that we are using the Lock type definition provided by the RecMutex class, not the one provided by the Mutex class.

See Also