如何使用递归QMutex

时间:2012-11-30 01:47:19

标签: c++ qt mutex recursive-mutex

我正在尝试使用递归QMutex,我阅读了QMutex类参考,但我不明白该怎么做,有人可以举个例子吗? 我需要一些方法来锁定QMutex,可以在调用lock方法之后或之前解锁。 如果递归互斥不是那么有其他方式吗?

3 个答案:

答案 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的调用是平衡的。

在非递归模式下,这将导致死锁。