1. 避免嵌套锁, 如果每个线程都只占有一个锁, 则可以很大程度上避免死锁。
其死锁的情况是, 线程 1 依次获得 A 对象和 B 对象的锁, 然后决定等另一个线程的信号再继续, 从而先释放了 B 对象的的锁。
可是线程 2 需要同时拥有对象 A 和对象 B 的锁才能向线程 1 发信号。
从而导致, 线程 2 因无法获得对象 A 上的锁, 因而阻塞, 等待线程 1 释放对象 A 上的锁。 而同时线程 1 也一直阻塞, 等待线程 2 的信号, 因此不会释放对象 A 的锁。

2. 用固定的顺序获取锁
如果非要同时拥有多个锁, 同时无法拥有单个的锁, 那么最好的处理方式是以固定的顺序得到他们。典型的情况是在一个链表的结构中, 如果要取得节点 B 的锁, 那么需要先取得节点 A 的锁, 接着取得节点 C 的锁。

3. 设置优先级
当多个锁存在时, 设立优先级是个好主意,这样可以避免低优先级的 mutex 会先于高优先级的拥有锁。例如以下代码:

hierarchical_mutex high_level_mutex(10000);
hierarchical_mutex  low_level_mutex(5000);int do_low_level_stuff();int low_level_func()
{lock_guard<hierarchical_mutex> lk(low_level_mutex);return do_low_level_stuff();
}void high_level_stuff(int some_param);void high_level_func()
{lock_guard<hierarchical_mutex> lk(high_level_mutex);high_level_stuff(low_level_func);
}void thread_a()
{high_level_func();
}hierarchical_mutex other_mutex(100);
void do_other_stuff();void other_stuff()
{high_levek_func();do_other_stuff();
}void thread_b()
{lock_guard<hierarchical_mutex> lk(other_mutex);other_stuff();
}

其中, thread_a 就会成功, 而 therad_b 就会运行出错。
为啥呢?
因为它首先会拥有 other_mutex 的锁,other_mutex 的优先级只有 100, 却在  high_level_mutex 前得到锁, 这违反了优先级, 所以 hierarchical_mutex 会报错并抛出一个异常, 然后退出程序。
上文中提到的 hierarchical_mutex 并不是标准库的一部分, 但是可以很容易的实现:

class hierarchical_mutex
{mutex                                   internal_mutex;unsigned long const                     hierarchy_value;unsigned                                previous_hierarchy_value;static  thread_local unsigned long    this_thread_hierarchy_value;// second mutex must now be less than //that of the mutex already held   //in order for the check to passvoid check_for_hierarcy_violation(){if(this_thread_hierarchy_value <= hierarchy_value){throw std::logic_error("mutex hierarchical violated");}}void update_hierarchy_value(){previous_hierarchy_value     = this_thread_hierarchy_value;this_thread_hierarchy_value = hierarchy_value;}
public:explicit hierarchical_mutex(unsigned long value): hierarchy_value(value),previous_hierarchy_value(0){}void lock(){check_for_hierarcy_violation();internal_mutex.lock();update_hierarchy_value();}void unlock(){this_thread_hierarchy_value = previous_hierarchy_value;internal_mutex.unlock();}bool try_lock(){check_for_hierarcy_violation();if(!internal_mutex.try_lock()){return false;}update_hierarchy_value();return true;}
};// initialized to the maximum value,
// so initially any mutex can be locked
thread_local unsigned longhierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX);

转载于:https://www.cnblogs.com/wuOverflow/p/4298804.html

避免死锁的一些注意事项相关推荐

  1. 独特视角带你走进Java并发编程的世界

    独特视角带你走进Java并发编程的世界 全局概括 并发问题产生的三个根本原因 java内存模型: 有序性和可见性的解决方案 volatile关键字 Happens-Before规则 锁: 原子性的解决 ...

  2. mysql innodb博客_细聊MySQL的Innodb存储引擎(完)

    上篇主要和大家探讨了Innodb引擎中出现幻读的处理方法与死锁的探测及避免死锁的一些注意事项.此篇,我们来研究下Innodb的索引. Innodb里涉及到的索引主要有四种,分别为聚簇索引(Cluste ...

  3. golang 中 channel 的详细使用、使用注意事项及死锁分析

    什么是 channel 管道 它是一个数据管道,可以往里面写数据,从里面读数据. channel 是 goroutine 之间数据通信桥梁,而且是线程安全的. channel 遵循先进先出原则. 写入 ...

  4. 详解synchronized锁的各种用法及注意事项

    1 前言 本文主要通过简单的demo来阐述synchronized锁的各种用法以及使用synchronized锁的相关注意事项,记录下来同时也方便自己记忆. synchronized锁是jvm内置的锁 ...

  5. 8000字 | 32 张图 | 一文搞懂事务+隔离级别+阻塞+死锁

    来源 | 悟空聊架构(ID:PassJava666) 本篇主要内容如下: 本篇主要内容 一.事务 1.1 什么是事务 为单个工作单元而执行的一系列操作.如查询.修改数据.修改数据定义. 1.2 语法 ...

  6. 大佬带你详解Python反爬虫措施以及爬虫编写注意事项

    Python爬虫开发:反爬虫措施以及爬虫编写注意事项 反爬虫的几重措施 1.IP限制 如果是个人编写的爬虫,IP可能是固定的,那么发现某个IP请求过于频繁并且短时间内访问大量的页面,有爬虫的嫌疑,作为 ...

  7. 总结sqlserver数据库性能优化相关的注意事项

    一.分析阶段一般来说,在系统分析阶段往往有太多需要关注的地方,系统各种功能性.可用性.可靠性.安全性需求往往吸引了我们大部分的注意力,但是,我们必须注意,性能是很重要的非功能性需求,必须根据系统的特点 ...

  8. 浅谈线程池(下):相关试验及注意事项

    三个月,整整三个月了,我忽然发现我还有三个月前的一个小系列的文章没有结束,我还欠一个试验!线程池是.NET中的重要组件,几乎所有的异步功能依赖于线程池.之前我们讨论了线程池的作用.独立线程池的存在意义 ...

  9. 如何控制并发和控制死锁(内含pb的处理要点)

    锁的概述 一. 为什么要引入锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 丢失更新 A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统 ...

最新文章

  1. UVA10003 切木棍 Cutting Sticks(区间DP、细节)
  2. 我在OSC的第一篇博文
  3. code Gym 100500D T-shirts(暴力)
  4. 存储1m图像错误_【1m 讲堂】“跨专业挑战空调施工常见错误,你敢来参加吗?”...
  5. 让TA们告诉你,疫情当下如何更彪悍的成长
  6. 前端学习(3103):vue+element今日头条管理-hello-react案例
  7. 操作系统之内存管理:1、内存管理基础知识(指令工作原理、地址转化、程序运行过程)
  8. mac: brew的删除
  9. java找出最高工资和下标_(java)leetcode852 山脉数组的封顶索引(二分查找法找出数组中最大值的下标)(Peak Index in a Mountain Array)...
  10. Hibernate 主键
  11. 网络工程师(软考中级-华为认证)
  12. RK61 RGB 蓝牙双模键盘使用说明
  13. 图形之可见面判别算法
  14. 《量化投资策略如何现额益简及PDF电子书下载
  15. 情境领导者-第六章、产生胜利者 故事
  16. 第22课:打包和发布 Electron 应用
  17. 玩游戏跳出计算机内存不足怎么办,电脑内存不足怎么办?电脑内存不足的解决方法...
  18. arecord录制音频和aplay播放音频用法说明
  19. 声卡loopback有什么用_解读声卡数据背后的秘密
  20. Win10 Python 3.7全流程安装教程及详细解释

热门文章

  1. HTTP中Get与Post的区别
  2. datagrid的正反双向排序
  3. 如何调试你的C#程序
  4. 运用.NET读写Windows注册编辑表
  5. 【Qt】Qt再学习(十四):QGraphicsView
  6. Ruby DSL介绍及其在测试数据构造中的使用(2)
  7. eureka需要替换吗_iOS第三方库Eureka实现定制动画详解(二):万变不离其宗-Row组件...
  8. php五只猴子分椰子_tubes五只雪茄_phillies雪茄五只装
  9. java如何被调用_java – 如何知道Parse.initialize()是否已被调用?
  10. nvidia命令不可用linux,在Linux命令行下如何正确配置nVIDIA显卡