How to use recursive QMutex

I am trying to use a recursive QMutex, I am reading a reference to the QMutex class, but I do not understand how to do this, can anyone give me an example? I need to somehow block QMutex, which can be unlocked after or before calling the lock method. If the recursive mutex is wrong, is there another way?

+4
source share
3 answers

To create a recursive QMutex, you simply pass QMutex::Recursive at build time, for example:

 QMutex mutex(QMutex::Recursive); int number = 6; void method1() { mutex.lock(); number *= 5; mutex.unlock(); } void method2() { mutex.lock(); number *= 3; mutex.unlock(); } 

Recursive means that you can block the mutex several times from one thread, you do not need to unlock it. If I understood your question well, what do you want.

Be careful if you lock recursively, you must call the unlock as many times. The best way to lock / unlock a mutex is QMutexLocker

 #include <QMutexLocker> QMutex mutex(QMutex::Recursive); int number = 6; void method1() { QMutexLocker locker(&mutex); // Here mutex is locked number *= 5; // Here locker goes out of scope. // When locker is destroyed automatically unlocks mutex } void method2() { QMutexLocker locker(&mutex); number *= 3; } 
+7
source

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(); // Does something to the resource void thud(); // Calls bar() then does something else to the resource private: Resource mRes; QMutex mLock; } 

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 } 
+3
source

Recursive mode means that if a thread owns a mutex and the same thread tries to lock the mutex again, it will succeed. The requirement is that lock/unlock calls are balanced.

In non-recursive mode, this will lead to a deadlock.

+2
source

All Articles