首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用递归QMutex

如何使用递归QMutex
EN

Stack Overflow用户
提问于 2012-11-30 09:47:19
回答 3查看 6.8K关注 0票数 5

我正在尝试使用递归类,我阅读了QMutex类参考,但我不知道如何做到这一点,有人能给我一个例子吗?我需要一些方法来锁定可以在调用QMutex方法之后或之前解锁的锁。如果递归互斥不是方法,还有其他方法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-12-01 05:14:58

要创建递归QMutex,只需在构造时传递QMutex::Recursive,例如:

代码语言:javascript
复制
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

代码语言:javascript
复制
#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;
}
票数 8
EN

Stack Overflow用户

发布于 2014-03-11 04:20:29

递归互斥锁可以从单个线程多次锁定,而不需要解锁,只要从同一线程进行相同数量的解锁调用即可。当一个共享资源被多个函数使用,并且其中一个函数调用另一个使用该资源的函数时,这种机制就派上用场了。

考虑下面的类:

代码语言:javascript
复制
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;
}

初始实现可能如下所示:

代码语言:javascript
复制
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中递归。

代码语言:javascript
复制
Foo::Foo() : mLock(QMutex::Recursive) {}

这是一个OK修复,适用于许多情况,但是应该意识到使用此解决方案可能会有性能损失,因为每个递归互斥调用可能需要一个系统调用来标识当前线程id。

除了线程id检查之外,对thud()的所有调用仍然执行QMutex::lock()两次!

需要递归的设计可以通过重构来消除对递归互斥的需求。一般来说,对递归互斥锁的需求是一种“代码气味”,表明需要坚持关注点分离的原则。

对于类Foo,可以想象创建一个私有函数调用来执行共享计算,并在公共接口级别保持资源锁定。

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2012-11-30 09:54:17

递归模式只是意味着,如果一个线程拥有一个互斥锁,而同一个线程再次尝试锁定该互斥锁,那么它将会成功。要求是对lock/unlock的调用是平衡的。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13637830

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档