再帰的なQMutexを使用しようとしています。QMutexクラスリファレンスを読みましたが、その方法がわかりません。誰かに例を教えてもらえますか?lockメソッドが呼び出された後または前にロックを解除できるQMutexをロックする方法が必要です。再帰的ミューテックスが方法ではない場合、他の方法はありますか?
3 に答える
再帰的なQMutexを作成するQMutex::Recursive
には、たとえば、構築時に渡すだけです。
QMutex mutex(QMutex::Recursive);
int number = 6;
void method1()
{
mutex.lock();
number *= 5;
mutex.unlock();
}
void method2()
{
mutex.lock();
number *= 3;
mutex.unlock();
}
Recursive
つまり、同じスレッドからミューテックスを数回ロックできるので、ロックを解除する必要はありません。私があなたの質問をよく理解していれば、それがあなたが望むものです。
再帰的にロックする場合は、同じ回数ロック解除を呼び出す必要があることに注意してください。ミューテックスをロック/ロック解除するためのより良い方法は、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;
}
再帰的ミューテックスは、同じスレッドから同じ数のロック解除呼び出しが行われる限り、ロックを解除する必要なしに、単一のスレッドから複数回ロックできます。このメカニズムは、共有リソースが複数の関数によって使用され、それらの関数の1つがリソースが使用されている別の関数を呼び出す場合に便利です。
次のクラスについて考えてみます。
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;
}
最初の実装は次のようになります。
Foo::Foo() {}
void Foo::bar() {
QMutexLocker locker(&mLock);
mRes.doSomething();
}
void Foo::thud() {
QMutexLocker locker(&mLock);
bar();
mRes.doSomethingElse();
}
上記のコードは、thudへの呼び出しでデッドロックします。mLockは、thud()の最初の行で取得され、再びbar()の最初の行で取得されます。これにより、thud()がロックを解放するのをブロックします。
簡単な解決策は、ctorでロックを再帰的にすることです。
Foo::Foo() : mLock(QMutex::Recursive) {}
これはOKの修正であり、多くの状況に適していますが、再帰的なミューテックス呼び出しごとに現在のスレッドIDを識別するためにシステムコールが必要になる可能性があるため、このソリューションを使用するとパフォーマンスが低下する可能性があることに注意してください。
スレッドIDチェックに加えて、thud()へのすべての呼び出しはQMutex :: lock()を2回実行します!
再帰を必要とする設計は、再帰的ミューテックスの必要性を排除するためにリファクタリングできる場合があります。一般に、再帰的ミューテックスの必要性は「コードの臭い」であり、関心の分離の原則に従う必要があることを示しています。
クラスFooの場合、共有計算を実行するプライベート関数呼び出しを作成し、パブリックインターフェイスレベルでリソースをロックし続けることを想像できます。
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
}
再帰モードとは、スレッドがミューテックスを所有していて、同じスレッドがミューテックスを再度ロックしようとした場合に成功することを意味します。要件は、への呼び出しのlock/unlock
バランスが取れていることです。
非再帰モードでは、これによりデッドロックが発生します。