我正在尝试使用递归QMutex,我阅读了QMutex类参考,但我不明白该怎么做,有人可以举个例子吗? 我需要一些方法来锁定QMutex,可以在调用lock方法之后或之前解锁。 如果递归互斥不是那么有其他方式吗?
答案 0 :(得分:8)
要创建递归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 :(得分:3)
只要从同一个线程进行相同数量的解锁调用,递归互斥锁就可以从单个线程多次锁定而无需解锁。当共享资源被多个函数使用时,这种机制会派上用场,其中一个函数调用另一个使用资源的函数。
考虑以下课程:
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的调用进行DEADLOCK。 mLock将在thud()的第一行获取,再次由bar()的第一行获取,这将阻止等待thud()释放锁。
一个简单的解决方案是在ctor中使锁递归。
Foo::Foo() : mLock(QMutex::Recursive) {}
这是一个好的修复程序,并且适用于许多情况,但是应该注意使用此解决方案可能会有性能损失,因为每个递归互斥锁调用可能需要系统调用来标识当前的线程ID。 / p>
除了线程id检查之外,对thud()的所有调用仍然执行QMutex :: lock()两次!
需要递归的设计可以重构,以消除对递归互斥锁的需要。一般来说,对递归互斥体的需求是“代码气味”,并表明需要遵守关注点分离的原则。
对于类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
}
答案 2 :(得分:2)
递归模式只是意味着如果一个线程拥有一个互斥锁,并且同一个线程试图再次锁定该互斥锁,那么这将成功。要求是对lock/unlock
的调用是平衡的。
在非递归模式下,这将导致死锁。