A recursive mutex can be blocked multiple times from a single thread without the need to unlock if the same number of unlock calls are made from a single thread. This mechanism is useful when a shared resource is used by more than one function, and one of these functions calls another function in which the resource is used.
Consider the following class:
class Foo { public: Foo(); void bar();
The initial implementation might look something like this:
Foo::Foo() {} void Foo::bar() { QMutexLocker locker(&mLock); mRes.doSomething(); } void Foo::thud() { QMutexLocker locker(&mLock); bar(); mRes.doSomethingElse(); }
The above code will be DEADLOCK on calls. mLock will be received in the first line of thud () and once again the first line of bar (), which blocks waiting for thud () to release the lock.
A simple solution would be to do a recursive lock in ctor.
Foo::Foo() : mLock(QMutex::Recursive) {}
This fix is OK and will be suitable for many situations, but keep in mind that using this solution may slow performance, because for each recursive call of the mutex, a system call may be required to identify the current stream identifier.
In addition to checking the thread identifier, all thud () calls do QMutex :: lock () twice more!
Constructs requiring recursive processing can be reorganized to eliminate the need for a recursive mutex. In general, the need for a recursive mutex is the "smell of code" and indicates the need to adhere to the principle of separation of problems.
For the Foo class, you can imagine creating a private function call that performs general computation and preserves resource locks at the public interface level.
class Foo { public: Foo(); void bar(); // Does something to the resource void thud(); // Does something then does something else to the resource private: void doSomething(); private: Resource mRes; QMutex mLock; } Foo::Foo() {} // public void Foo::bar() { QMutexLocker locker(&mLock); doSomething(); } void Foo::thud() { QMutexLocker locker(&mLock); doSomething(); mRes.doSomethingElse(); } // private void Foo::doSomething() { mRes.doSomething(); // Notice - no mutex in private function }