我正在尝试使用递归 QMutex,我阅读了 QMutex 类参考,但我不明白该怎么做,有人可以举个例子吗?我需要一些方法来锁定 QMutex,可以在调用 lock 方法之后或之前解锁。如果递归互斥锁不是方法,还有其他方法吗?
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
意味着您可以从同一个线程多次锁定互斥锁,而不必解锁它。如果我能很好地理解你的问题,那就是你想要的。
请注意,如果您以递归方式锁定,则必须调用 unlock 相同的次数。锁定/解锁互斥锁的更好方法是使用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;
}
递归互斥锁可以从单个线程多次锁定,而无需解锁,只要从同一线程进行相同数量的解锁调用即可。当一个以上的函数使用共享资源,并且其中一个函数调用另一个使用该资源的函数时,这种机制会派上用场。
考虑以下类:
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) {}
这是一个不错的修复,并且适用于许多情况,但是应该知道使用此解决方案可能会降低性能,因为每个递归互斥锁调用可能需要系统调用来识别当前线程 ID。
除了线程 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
}
递归模式只是意味着如果一个线程拥有一个互斥锁,并且同一个线程再次尝试锁定互斥锁,那将成功。要求是lock/unlock
平衡的调用。
在非递归模式下,这将导致死锁。