c++11 多线程编程(四)------ 死锁(Dead Lock)
死锁
如果你将某个mutex
上锁了,却一直不释放,另一个线程访问该锁保护的资源的时候,就会发生死锁,这种情况下使用lock_guard
可以保证析构的时候能够释放锁,然而,当一个操作需要使用两个互斥元的时候,仅仅使用lock_guard
并不能保证不会发生死锁,如下面的例子:
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <fstream>
using namespace std;class LogFile {std::mutex _mu;std::mutex _mu2;ofstream f;
public:LogFile() {f.open("log.txt");}~LogFile() {f.close();}void shared_print(string msg, int id) {std::lock_guard<std::mutex> guard(_mu);std::lock_guard<std::mutex> guard2(_mu2);f << msg << id << endl;cout << msg << id << endl;}void shared_print2(string msg, int id) {std::lock_guard<std::mutex> guard(_mu2);std::lock_guard<std::mutex> guard2(_mu);f << msg << id << endl;cout << msg << id << endl;}
};void function_1(LogFile& log) {for(int i=0; i>-100; i--)log.shared_print2(string("From t1: "), i);
}int main()
{LogFile log;std::thread t1(function_1, std::ref(log));for(int i=0; i<100; i++)log.shared_print(string("From main: "), i);t1.join();return 0;
}
运行之后,你会发现程序会卡住,这就是发生死锁了。程序运行可能会发生类似下面的情况:
Thread A Thread B
_mu.lock() _mu2.lock()//死锁 //死锁
_mu2.lock() _mu.lock()
解决办法有很多:
可以比较
mutex
的地址,每次都先锁地址小的,如:if(&_mu < &_mu2){_mu.lock();_mu2.unlock(); } else {_mu2.lock();_mu.lock(); }
使用层次锁,将互斥锁包装一下,给锁定义一个层次的属性,每次按层次由高到低的顺序上锁。
这两种办法其实都是严格规定上锁顺序,只不过实现方式不同。
c++
标准库中提供了std::lock()
函数,能够保证将多个互斥锁同时上锁,
std::lock(_mu, _mu2);
同时,lock_guard
也需要做修改,因为互斥锁已经被上锁了,那么lock_guard
构造的时候不应该上锁,只是需要在析构的时候释放锁就行了,使用std::adopt_lock
表示无需上锁:
std::lock_guard<std::mutex> guard(_mu2, std::adopt_lock);
std::lock_guard<std::mutex> guard2(_mu, std::adopt_lock);
完整代码如下:
#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <fstream>
using namespace std;class LogFile {std::mutex _mu;std::mutex _mu2;ofstream f;
public:LogFile() {f.open("log.txt");}~LogFile() {f.close();}void shared_print(string msg, int id) {std::lock(_mu, _mu2);std::lock_guard<std::mutex> guard(_mu, std::adopt_lock);std::lock_guard<std::mutex> guard2(_mu2, std::adopt_lock);f << msg << id << endl;cout << msg << id << endl;}void shared_print2(string msg, int id) {std::lock(_mu, _mu2);std::lock_guard<std::mutex> guard(_mu2, std::adopt_lock);std::lock_guard<std::mutex> guard2(_mu, std::adopt_lock);f << msg << id << endl;cout << msg << id << endl;}
};void function_1(LogFile& log) {for(int i=0; i>-100; i--)log.shared_print2(string("From t1: "), i);
}int main()
{LogFile log;std::thread t1(function_1, std::ref(log));for(int i=0; i<100; i++)log.shared_print(string("From main: "), i);t1.join();return 0;
}
总结一下,对于避免死锁,有以下几点建议:
建议尽量同时只对一个互斥锁上锁。
{std::lock_guard<std::mutex> guard(_mu2);//do somethingf << msg << id << endl; } {std::lock_guard<std::mutex> guard2(_mu);cout << msg << id << endl; }
不要在互斥锁保护的区域使用用户自定义的代码,因为用户的代码可能操作了其他的互斥锁。
{std::lock_guard<std::mutex> guard(_mu2);user_function(); // never do this!!!f << msg << id << endl; }
如果想同时对多个互斥锁上锁,要使用
std::lock()
。给锁定义顺序(使用层次锁,或者比较地址等),每次以同样的顺序进行上锁。详细介绍可看C++并发编程实战。
参考
- C++并发编程实战
- C++ Threading #4: Deadlock
c++11 多线程编程(四)------ 死锁(Dead Lock)相关推荐
- C++11多线程编程(八)——死锁问题
一.死锁现象 看到"死锁"二字,你是不是慌得不知所措.死锁,顾名思义就是这个锁死掉了,再也动不了了.那死锁是怎么产生的呢?当你对某个资源上锁后,却迟迟没有释放或者根本就无法释放,导 ...
- Linux与C++11多线程编程(学习笔记)
多线程编程与资源同步 在Windows下,主线程退出后,子线程也会被关闭; 在Linux下,主线程退出后,系统不会关闭子线程,这样就产生了僵尸进程 3.2.1创建线程 Linux 线程的创建 #inc ...
- c++11多线程编程同步——使用条件变量condition variable
简述 在多线程编程中,当多个线程之间需要进行某些同步机制时,如某个线程的执行需要另一个线程完成后才能进行,可以使用条件变量. c++11提供的 condition_variable 类是一个同步原语, ...
- Java - 死锁 Dead Lock 定位分析
文章目录 Pre jstack Thread dump Dead Lock 分析 分析代码 解决 Pre JVM-11虚拟机性能监控与故障处理工具之[JDK的可视化工具-JConsole] jstac ...
- c++11 多线程编程(六)------条件变量(Condition Variable)
互斥锁std::mutex是一种最常见的线程间同步的手段,但是在有些情况下不太高效. 假设想实现一个简单的消费者生产者模型,一个线程往队列中放入数据,一个线程往队列中取数据,取数据前需要判断一下队列中 ...
- c++11 多线程编程(三)------ 竞争和互斥锁
竞争条件 并发代码中最常见的错误之一就是竞争条件(race condition).而其中最常见的就是数据竞争(data race),从整体上来看,所有线程之间共享数据的问题,都是修改数据导致的,如果所 ...
- c++11 多线程编程(一)------初始
什么是并发 并发在生活中随处可见,边走路边说话,边听歌边写代码.计算机术语中的"并发",指的是在单个系统里同时执行多个独立的活动,而不是顺序的一个接一个的执行.对于单核CPU来说, ...
- 多线程编程 ----- 四种同步方法
多线程,就是在一个进程里除主线程外创建其他的线程为进程工作,为什么要使用多线程?因为使用多线程在多数情况下都能提升运行速度.多线程主要的应用场景有 避免阻塞(异步调用) 比如你用一般模型的socket ...
- java安全编码指南之:死锁dead lock
文章目录 简介 不同的加锁顺序 使用private类变量 使用相同的Order 释放掉已占有的锁 简介 java中为了保证共享数据的安全性,我们引入了锁的机制.有了锁就有可能产生死锁. 死锁的原因就是 ...
最新文章
- 编译-链接-运行-环境配置各种error汇总
- OSPF:MTU不一致导致的邻接关系问题
- 使用Selenium模拟浏览器,实现自动爬取数据
- python 对axis的理解
- OC 方法,继承,特殊方法
- gdpr合规性测试_使用生产数据在GDPR后世界进行测试
- TypeScript学习(八):数组的补充及内置对象说明
- 数据结构之线性表之顺序存储结构(3)
- 网络_检测公网端口是否开启
- Elasticsearch Index Template(索引模板)
- Webgoat学习笔记1
- 从本机复制文件到VM虚拟机出现卡死
- WiFiDisplay
- python no such file or directory_python No such file or Directory
- CSS基础的文字样式
- 计算机桌面文件删除不掉是怎么了,桌面上文件删不掉_桌面上的压缩文件为什么删除不了?...
- 艾可森 mysql,国足进世界杯有戏!巴西归化球员表决心:中国对我好,我必须努力...
- LeeCode1468. 计算税后工资
- LinkedList源码浅析
- 新手零基础快速入门Docker
热门文章
- 选出一个从零到五十之间的数,要求能被3整除且一位上的数为5
- 《阿甘正传》,看了很多遍,是否留意到这个镜头???
- Q123:PBRT-V3,各种形式的“光传播方程”的推导依据
- Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行——怎么将Unix/Mac系统下的文件转换到Windows系统下
- 计算机专业岗位细分及学习必备清单
- 如何选择大数据软件开发公司
- php curl 请求失败,PHP CURL库之GET、POST数据大小限制导致请求失败解决方案
- 有服主传送玩家指令_我的世界:不用指令能够到达边境之地吗?实验证明,根本就不可能...
- HTML使川锚标签,第1章HTML的基本标签祥解.ppt
- mysql 日志mixed模式_[MySQL binlog]彻底解析Mixed日志格式的binlog