博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++11线程指南(8)--死锁
阅读量:4070 次
发布时间:2019-05-25

本文共 1593 字,大约阅读时间需要 5 分钟。

目录


1.死锁介绍

  当多个mutex存在的时候,可能就会产生死锁。

  避免死锁的一个最通用的方法是,总是按照相同的顺序来锁定两个mutex, 即总是先于mutex B之前lock mutex A,这样就不会有死锁的可能。有时候这种方法很简单实用,当这些mutex用于不同的目标时。
  但是,当mutex用于包含相同类的一个实例时,就不是那么容易了。
  例如,下面程序所示,相同类的两个实例之间交互数据。为了保证数据交互不受并发影响,两个实例都使用mutex进行保护。但是当mutex被嵌套的调用时,就形成了死锁。
  然而,C++标准库中的std::lock可以解决死锁,它能同时的lock多个mutex,而不会形成死锁。

#include 
class Dummy {};void swap(Dummy& lhs,Dummy& rhs);class A{private: Dummy myObj; std::mutex mu;public: A(Dummy const& obj):myObj(obj){} friend void swap(A& lhs, A& rhs) { //需要先检测这两个实例是否相同。因为如果在一个已经被获取到的std::mutex上, //试图再次获取锁,这会导致未知的行为。 if(&lhs==&rhs) return; // 调用std::lock()来锁定这两个mutex。 std::lock(lhs.mu,rhs.mu); // 构造两个std::lock_guard实例,每个对应一个mutex。 std::lock_guard
lock_a(lhs.mu,std::adopt_lock); std::lock_guard
lock_b(rhs.mu,std::adopt_lock); swap(lhs.myObj, rhs.myObj); }};

  swap函数开始会检测参数是否相同,因为重复去lock一个已经被锁定了的std::mutex会导致未知行为。如果需要支持重复的lock, 可以采用std::recursive_mutex。

  然后,调用std::lock()来锁定两个mutexes,接着构造了两个std::lock_guard实例。
  参数std::adopt_lock用来告诉std::lock_guard,传入的mutex已经被lock了,它们仅能拥有mutex上面已经存在的锁的使用权,而不能在构造函数中再次lock the mutex.
  这就确保了mutex在函数退出时,或抛出异常时,能被准确的unlock。 另外,如果std::lock成功地在一个mutex上lock, 但是lock另一个mutex时抛出了异常,前一个被锁的mutex会被自动释放。std::lock提供了all-or-nothing机制。
  尽管std::lock能帮组我们需要一起获取多个mutex时,避免死锁。但是,分别获取多个mutex时,却无能为力。这种情况下,就需要开发人员自己来避免出现死锁了。这不是件容易的事情,因为死锁是多线程代码中最可能出现的问题。不过,还是存在一些规则来避免死锁。

2.避免死锁

  尽管锁是出现在死锁中的最常见的要素,但是死锁并不只是会占用锁。我们可以在两个线程之间,不使用锁来创建一个死锁,例如,两个std:thread object相互调用join()。

  这个简单的死循环可以发生在任何地方,如果一个线程等待另一个线程执行,而另一个线程又在等待这个线程。除了两个线程,多个线程之间同样也可能出现死锁。
  一个原则是,如果另外一个线程可能会依赖当前线程,则不要再让当前线程依赖那个线程了。

 

转载地址:http://dmeji.baihongyu.com/

你可能感兴趣的文章
如何成为编程高手
查看>>
本科生的编程水平到底有多高
查看>>
备忘:java中的递归
查看>>
Solr及Spring-Data-Solr入门学习
查看>>
python_time模块
查看>>
python_configparser(解析ini)
查看>>
selenium学习资料
查看>>
<转>文档视图指针互获
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
javascript传参字符串 与引号的嵌套调用
查看>>
swiper插件的的使用
查看>>
layui插件的使用
查看>>
JS牛客网编译环境的使用
查看>>
9、VUE面经
查看>>
Golang 数据可视化利器 go-echarts ,实际使用
查看>>
mysql 跨机器查询,使用dblink
查看>>
mysql5.6.34 升级到mysql5.7.32
查看>>
dba 常用查询
查看>>