首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在设计线程安全类时避免嵌套调用时的死锁

在设计线程安全类时避免嵌套调用时的死锁
EN

Stack Overflow用户
提问于 2017-01-01 16:04:27
回答 4查看 3.6K关注 0票数 3

我知道我可以在类中使用mutex成员,并将其锁定在每个方法中,以防止多线程环境中的数据竞争。但是,如果类的方法中存在嵌套调用,比如类下面的add_one()add_two(),这种方法可能会导致死锁。对每个方法使用不同的mutex是一个解决办法。但是,在嵌套调用的情况下,是否有更有原则和优雅的方法来防止死锁呢?

代码语言:javascript
复制
class AddClass {
public:
  AddClass& operator=(AddClass const&) = delete; // disable copy-assignment constructor
  AddClass(int val) : base(val) {}
  int add_one() { return ++base; }
  int add_two() { 
    add_one; 
    add_one;
    return base;
  }
private:
  int base;
};
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-01-01 16:08:25

std::recursive_mutex正是为此目的而存在的。

另一种避免递归互斥产生开销的方法是将公共同步接口与私有非同步实现分开:

代码语言:javascript
复制
class AddClass {
public:
  AddClass& operator=(AddClass const&) = delete; // disable copy-assignment constructor
  AddClass(int val) : base(val) {}
  int add_one() {
     std::lock_guard<std::mutex> guard{mutex};
     return add_one_impl();
  }
  int add_two() {
     std::lock_guard<std::mutex> guard{mutex};
     return add_two_impl();
  }
private:
  int base;
  std::mutex mutex;
  int add_one_impl() { 
    return ++base;
  }
  int add_two_impl() { 
    add_one_impl(); 
    add_one_impl();
    return base;
  }
};

但是,请注意,这并不总是可能的。例如,如果有一个方法接受回调并在持有锁时调用回调,则回调可能尝试调用类的其他公共方法,并且再次面临双重锁定尝试。

票数 8
EN

Stack Overflow用户

发布于 2017-01-01 16:13:56

递归互斥对象是一个可锁定的对象,就像互斥对象一样,但允许同一个线程获得对互斥对象的多级所有权。

何时和如何使用递归互斥--下面的链接

递归互斥

注意:递归互斥和非递归互斥有不同的用例。

希望能帮上忙。

票数 1
EN

Stack Overflow用户

发布于 2017-01-01 16:07:01

这方面的一般解决方案称为重入互斥

虽然在普通互斥锁( lock )上执行“锁”操作的任何尝试都将在互斥锁已经锁定时失败或阻塞,但在递归互斥锁上,只有当锁定线程已经持有该锁时,此操作才会成功。通常,递归互斥锁跟踪它被锁定的次数,并要求在其他线程锁定它之前执行同样多的解锁操作。

C++11标准库中有一个:互斥

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

https://stackoverflow.com/questions/41416794

复制
相关文章

相似问题

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