要以相同顺序获取多个锁

多线程在加锁解锁时,可能会出现死锁问题,比如,

线程 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)的更多相关文章

  1. c++多线程崩溃错误1

    主线程中的子线程没有jion,导致主线程马上结束,子线程对象被释放掉,而子线程还在后台继续执行导致崩溃 int main() OBJ = classA() OBJ.START()//在start函数中 ...

  2. Java SE之快速失败(Fast-Fail)与快速安全(Fast-Safe)的区别[集合与多线程/增强For](彻底详解)

    声明 特点:基于JDK源码进行分析. 研究费时费力,如需转载或摘要,请显著处注明出处,以尊重劳动研究成果:博客园 - https://www.cnblogs.com/johnnyzen/p/10547 ...

  3. Java多线程知识总结(一)

    一.创建线程的三种方式: 创建线程的方式有三种,一是创建Thread实例,二是实现Runnable接口,三是实现Callable接口,Runnable接口和Callable接口的区别是一个无返回值,一 ...

  4. Java回顾之多线程同步

    在这篇文章里,我们关注线程同步的话题.这是比多线程更复杂,稍不留意,我们就会“掉到坑里”,而且和单线程程序不同,多线程的错误是否每次都出现,也是不固定的,这给调试也带来了很大的挑战. 在这篇文章里,我 ...

  5. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  6. 转:最近5年133个Java面试问题列表

    最近5年133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来 ...

  7. [转载]hashmap hashtable 的区别

    Hashtable 和 HashMap 做为 Map 的基本特性 两者都实现了Map接口,基本特性相同 -          对同一个Key,只会有一个对应的value值存在 -          如 ...

  8. Java笔试题解答和部分面试题

    面试类  银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...

  9. Java 集合系列 11 hashmap 和 hashtable 的区别

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  10. 面试题_76_to_81_Java 最佳实践的面试问题

    包含 Java 中各个部分的最佳实践,如集合,字符串,IO,多线程,错误和异常处理,设计模式等等. 76)Java 中,编写多线程程序的时候你会遵循哪些最佳实践?(答案)这是我在写Java 并发程序的 ...

随机推荐

  1. [转帖]Codis作者黄东旭:细说分布式Redis架构设计和那些踩过的坑

    https://dbaplus.cn/news-141-270-1.html Codis是一个分布式Redis解决方案,与官方的纯P2P模式不同,Codis采用的是Proxy-based的方案.今天我 ...

  2. [转帖]Titan 配置

    https://www.bookstack.cn/read/TiDB-4.0/storage-engine-titan-configuration.md 开启 Titan Titan 对 RocksD ...

  3. jconsole的简单学习

    摘要 jconsole 是JDK自带的一款图形化监测工具 他可以监测本地程序,也可以检测远程的机器 在没有其他监控手段可以使用的情况下可以快速进行必要的监测 使用方法也比较简单. 本地监控 jcons ...

  4. 【构造,图论,建模】Loj3629「2021 集训队互测」序列

    Problem Link 有一个长为 \(n\) 的未知序列,给定 \(m\) 个限制,每个限制形如给定 \(i,j,k,x\),要求 \(a_i,a_j,a_k\) 的中位数为 \(x\).构造一个 ...

  5. Git - 关联远程仓库以及同时使用Lab和Hub

    更新一下,感觉有更简单的方式 就比如你git config 的 全局的name和email是lab的 那就clone github上的项目然后设置局部的name和email就行了 ********** ...

  6. ABP 使用Except 和EqualityHelper<T> 实现去重

    先上一端代码!!! railwayCar中有10条记录,train参考railwayCar创建了5条记录.要实现,当train再次参考railwayCar创建记录时,使用过的记录在展示列表时不可以再次 ...

  7. TienChin-课程管理-课程搜索

    后端 新建 CourseVO.java: /** * CourseVO类是一个课程的值对象,用于存储课程的相关信息. * 它包含了课程的名称.类型.适用对象.最低价格和最高价格等属性. */ publ ...

  8. IServiceBehavior, IOperationBehavior,IParameterInspector

    1 public class MyOperationBehavior:Attribute, IOperationBehavior 2 { 3 public void AddBindingParamet ...

  9. batch size设置技巧

    1.什么是BatchSize Batch一般被翻译为批量,设置batch_size的目的让模型在训练过程中每次选择批量的数据来进行处理.Batch Size的直观理解就是一次训练所选取的样本数. Ba ...

  10. PGL图学习之图游走类metapath2vec模型[系列五]

    PGL图学习之图游走类metapath2vec模型[系列五] 本项目链接:https://aistudio.baidu.com/aistudio/projectdetail/5009827?contr ...