C++ 多线程的错误和如何避免(7)
要以相同顺序获取多个锁
多线程在加锁解锁时,可能会出现死锁问题,比如,
线程 1 在加锁 mutex A 后,继续尝试获取 mutex B,而 mutex B 已经被线程 2 获取,而线程 2 在等待获取 mutex A,mutex B 只有线程 2 获取 mutex A 后才能解锁,
这就导致线程 1 和线程 2 互相等待锁,而这一操作就是死锁情况,容易导致程序挂起。

使用代码模拟死锁场景:
#include <iostream>
#include <string>
#include <thread>
#include <mutex> using namespace std; std::mutex muA;
std::mutex muB; void CallHome_AB(string message)
{
muA.lock();
//Some additional processing
std::this_thread::sleep_for(std::chrono::milliseconds(100));
muB.lock(); cout << "Thread " << this_thread::get_id() << " says " << message << endl; muB.unlock();
muA.unlock();
} void CallHome_BA(string message)
{
muB.lock();
//Some additional processing
std::this_thread::sleep_for(std::chrono::milliseconds(100));
muA.lock(); cout << "Thread " << this_thread::get_id() << " says " << message << endl; muA.unlock();
muB.unlock();
} int main()
{
thread t1(CallHome_AB, "Hello from Jupiter");
thread t2(CallHome_BA, "Hello from Pluto"); t1.join();
t2.join(); return 0;
}
运行后,会发现控制台没有打印任何字符串,因为两个线程都尝试获取对方的锁,导致了死锁
如何解决?
最好的办法就是所有的锁都可以以相同的顺序获得,比如线程 1 顺序获得 mutex A 和 mutex B,再释放 mutex B 和 mutex A,线程 2 也顺序获得 mutex A 和 B,再顺序释放
std::mutex muA;
std::mutex muB; void CallHome_AB(string message) {
muA.lock();
// Some additional processing
std::this_thread::sleep_for(std::chrono::milliseconds(100));
muB.lock(); cout << "Thread " << this_thread::get_id() << " says " << message << endl; muB.unlock();
muA.unlock();
} void CallHome_BA(string message) {
muA.lock();
// Some additional processing
std::this_thread::sleep_for(std::chrono::milliseconds(100));
muB.lock(); cout << "Thread " << this_thread::get_id() << " says " << message << endl; muB.unlock();
muA.unlock();
}
当然目前也有封装好的 C++ 函数来同时获得两个锁,如下
std::scoped_lock lock{muA, muB};
The class scoped_lockis a mutex wrapper that provides a convenient RAII-style mechanism for owning one or more mutexes for the duration of a scoped block.
When a scoped_lock object is created, it attempts to take ownership of the mutexes it is given. When control leaves the scope in which the scoped_lock object was created, the scoped_lock is destructed and the mutexes are released. If several mutexes are given, deadlock avoidance algorithm is used as if by std::lock.
或者我们也可以用 std::timed_mutex 来解决这个问题,当超过一定时间后自动释放锁
The timed_mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.
C++ 多线程的错误和如何避免(7)的更多相关文章
- c++多线程崩溃错误1
主线程中的子线程没有jion,导致主线程马上结束,子线程对象被释放掉,而子线程还在后台继续执行导致崩溃 int main() OBJ = classA() OBJ.START()//在start函数中 ...
- Java SE之快速失败(Fast-Fail)与快速安全(Fast-Safe)的区别[集合与多线程/增强For](彻底详解)
声明 特点:基于JDK源码进行分析. 研究费时费力,如需转载或摘要,请显著处注明出处,以尊重劳动研究成果:博客园 - https://www.cnblogs.com/johnnyzen/p/10547 ...
- Java多线程知识总结(一)
一.创建线程的三种方式: 创建线程的方式有三种,一是创建Thread实例,二是实现Runnable接口,三是实现Callable接口,Runnable接口和Callable接口的区别是一个无返回值,一 ...
- Java回顾之多线程同步
在这篇文章里,我们关注线程同步的话题.这是比多线程更复杂,稍不留意,我们就会“掉到坑里”,而且和单线程程序不同,多线程的错误是否每次都出现,也是不固定的,这给调试也带来了很大的挑战. 在这篇文章里,我 ...
- 2019年北航OO第二单元(多线程电梯任务)总结
一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...
- 转:最近5年133个Java面试问题列表
最近5年133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来 ...
- [转载]hashmap hashtable 的区别
Hashtable 和 HashMap 做为 Map 的基本特性 两者都实现了Map接口,基本特性相同 - 对同一个Key,只会有一个对应的value值存在 - 如 ...
- Java笔试题解答和部分面试题
面试类 银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...
- Java 集合系列 11 hashmap 和 hashtable 的区别
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- 面试题_76_to_81_Java 最佳实践的面试问题
包含 Java 中各个部分的最佳实践,如集合,字符串,IO,多线程,错误和异常处理,设计模式等等. 76)Java 中,编写多线程程序的时候你会遵循哪些最佳实践?(答案)这是我在写Java 并发程序的 ...
随机推荐
- Numa以及其他内存参数等对Oracle的影响
Numa以及其他内存参数等对Oracle的影响 背景知识: Numa的理解 Numa 分一致性内存访问结构 主要是对应UMA 一致性内存访问而言的. 在最初一个服务器只有一个CPU的场景下, 都是UM ...
- [转帖][译]tcpdump 示例教程
https://colobu.com/2019/07/16/a-tcpdump-tutorial-with-examples/ 目录 [−] 基于IP查找流量 根据来源和目标进行筛选 根据网段进行查找 ...
- 【转帖】mysql一个索引块有多少指针_深刻理解MySQL系列之索引
索引 查找一条数据的过程 先看下InnoDB的逻辑存储结构:node 表空间:能够看作是InnoDB存储引擎逻辑结构的最高层,全部的数据都存放在表空间中.默认有个共享表空间ibdata1.若是启用in ...
- Windows 和 linux 下面 Redis 性能比较
Windows 和 linux 下面 Redis 性能比较 问题来源 公司里面有一些环境还是使用Windows来跑 对应的. Redis和nginx 也是跑在Windows上面 但是微软官网自从 3. ...
- 在线获取所有依赖rpm包的方法
背景 现在经常有一些不能上网的LInux机器但是需要安装一些软件. 但是有时候经常因为有依赖关系找不到的情况比较麻烦. 或者是一些公司的网络总是受限,网络速度非常慢. 下载安装非常折磨人. 这个时候就 ...
- Go-操作redis/redigo
目录 Go-操作redis 安装 连接 使用 设置key过期时间 批量获取mget.批量设置mset 列表操作 hash操作 Pipelining(管道) redis发布会订阅模式 事务操作 万能操作 ...
- 快捷方式 ABP——切换MySQL数据库
当基于ABP开发一段时间后,切换数据库可以使用快捷方式 方法如下: 第一步: 前提是要知道所使用的数据库的版本 1. vs 2017需要点击XXX.XXX.EntityFrameworkCore,右键 ...
- 年末将至,Java 开发者必须了解的 16 个Java 顶级开源项目!
年末将至,值得你关注的16个Java 开源项目! 本文已经收录自笔者开源的 JavaGuide: https://github.com/Snailclimb/JavaGuide ([Java学习+面试 ...
- Python 实现专属字典生成器
编写一个密码生成工具,这里我们使用弱密码与个性化数组组合形成一个定制字典,例如收集用户的姓名,昵称,QQ号手机号等资源,然后通过Python对搜集到的数据与弱密码进行结合,从而定制出属于某个人的专属密 ...
- STM32CubeMX教程29 USB_HOST - 使用FatFs文件系统读写U盘
1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 ...