linux死锁检测的一种思路【转】
转自:http://www.cnblogs.com/mumuxinfei/p/4365697.html
前言: 
  上一篇博文讲述了pstack的使用和原理. 和jstack一样, pstack能获取进程的线程堆栈快照, 方便检验和性能评估. 但jstack功能更加的强大, 它能对潜在的死锁予以提示, 而pstack只提供了线索, 需要gdb进一步的确定. 
  那Linux下, 如何去检测死锁, 如何让死锁的检测能够更加的智能和方便? 这是本文的核心主旨, 让我们一同分享下思路.
常规做法:
  我们来模拟一个出现死锁的程序, 然后通过常规方式来确定是否出现了死锁, 以及在那些线程上出现的.
  如下是经典的死锁程序:
  注: 线程A获取锁1, 线程B获取锁2, 然后线程A/B分别去获取锁2/1, 两者谁也不松手的, 又不得对方的, 于是duang, duang duang...
  使用pstack来快速扫描堆栈:
  
  发现有两个线程均在lock中等待, 存在死锁的嫌疑, 需要gdb后具体确认.
  
  图文解读: 线程10800申请mutex_1(此时被线程10799所有), 而线程10799申请mutex_2(被线程10800所有), 于是线程10800在等待线程10799的释放, 而线程10799在等待线程10800的释放, 于是我们可以确定发生死锁了.
  但这种方式, 需要开发人员自己去验证和排除, 复杂的案例就并不轻松了. 
  在gdb中, 我们可以只能看到mutex对应的线程, 却无法反向获取到线程拥有的mutex列表, 如果有这个信息, 就像jstack工具那样, 获取对死锁的判定, 只要扫下堆栈信息, 就能基本的判定了.
检测模型:
  对于死锁, 操作系统课程中, 着重讲述了其常规模型/检测算法/规避建议, 这边不再展开.
  一言以蔽之: 死锁的发生, 必然意味着有向图(依赖关系)的构建存在环.
  关于检测模型, 我们可以这么假定, 锁为有向边, 申请锁的线程A为起点, 拥有锁的线程B为终点. 这样就形成线程A到线程B的一条有向边. 而众多的锁(边)和线程(点), 就构成了一个有向图.
  于是乎, 一个死锁检测的算法, 就转变为图论中有向图的环判断问题. 而该问题, 可以借助成熟的拓扑遍历算法轻易实现.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //拓扑排序:可以测试一个有向图是否有环  voidGraph::topsort( ) {     Queue<Vertex> q;     intcounter = 0;     q.makeEmpty( );     foreach Vertex v         if( v.indegree == 0 )             q.enqueue( v );     while( !q.isEmpty( ) )     {         Vertex v = q.dequeue( );         counter++;        foreach Vertex w adjacent to v             if( --w.indegree == 0 )                 q.enqueue( w );     }     if( counter != NUM_VERTICES )         throwCycleFoundException( ); } | 
解决方案:
  检测模型的确定, 让人豁然开朗. 但如何落地实现, 成了另一个拦路虎. 
  让我们从反向获取线程拥有的锁列表这个思路出发, 如何去实现? 如果我们能像java反射一样, 拦截lock/unlock操作, 并添加汇报线程与锁关系的功能, 那自然能构建有向图. 进而实现自动检测死锁情况.
  但是C/C++没有反射, 不过可以在所有的lock/unlock代码处添加桩代码, 并得以解决. 但这对使用方的代码具有侵入性, 能否改善呢?
  上天总是眷顾勤奋的人, 这边我们可以借助宏扩展(宏不会递归展开, 这是关键)来巧妙实现这个功能.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <sys/syscall.h>#define gettid() syscall(__NR_gettid)// 拦截lock, 添加before, after操作, 记录锁与线程的关系#define pthread_mutex_lock(x)                                            \    do{                                                                 \        printf("before=>thread_id:%d apply mutex:%p\n", gettid(), x);    \        pthread_mutex_lock(x);                                           \        printf("after=>thread_id:%d acquire mutex:%p\n", gettid(), x);   \    } while(false);// 拦截unlock, 添加after操作, 解除锁和线程的关系#define pthread_mutex_unlock(x)                                          \    do{                                                                 \        pthread_mutex_unlock(x);                                         \        printf("unlock=>thread_id: %d release mutex:%p\n", gettid(), x); \    } while(false); | 
  注: gettid函数用于获取线程实际的id, 重名名的pthread_mutex_lock/pthread_mutex_unlock宏, 添加了对before/after拦截调用, 并汇报记录了锁与线程的关系.
  我们可以对before/after操作, 进行实际的图构建和检测. 而且该宏替换, 轻松解决了代码侵入性的问题.
  让我们在回忆jstack的使用, 猜测java就是借助反射, 轻松实现了类似的功能, 使得其能检测死锁情况.
检验效果:
  有了上述的理论基础和思路后, 进行尝试和扩展. 
  这边写了一个简单的检测工具库, 使用非常的简单.
  在需要检测的代码中, 引入dead_lock_stub.h头文件, 然后在main函数的开头加入
| 1 | DeadLockGraphic::getInstance().start_check(); | 
  实验效果如下:
  
  样例代码的网盘地址如下: http://pan.baidu.com/s/1ntzHEeX
 写在最后:
  如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.
  
linux死锁检测的一种思路【转】的更多相关文章
- linux死锁检测的一种思路
		前言: 上一篇博文讲述了pstack的使用和原理. 和jstack一样, pstack能获取进程的线程堆栈快照, 方便检验和性能评估. 但jstack功能更加的强大, 它能对潜在的死锁予以提示, 而p ... 
- Linux死锁检测-Lockdep
		关键词:LockDep.spinlock.mutex. lockdep是内核提供协助发现死锁问题的功能. 本文首先介绍何为lockdep,然后如何在内核使能lockdep,并简单分析内核lockdep ... 
- Linux内核死锁检测机制【转】
		转自:http://www.oenhan.com/kernel-deadlock-check 死锁就是多个进程(线程)因为等待别的进程已占有的自己所需要的资源而陷入阻塞的一种状态,死锁状态一旦形成,进 ... 
- 浅谈linux的死锁检测 【转】
		转自:http://www.blog.chinaunix.net/uid-25942458-id-3823545.html 死锁:就是多个进程(≥2)因为争夺资源而相互等待的一种现象,若无外力推动,将 ... 
- 对抗栈帧地址随机化/ASLR的两种思路和一些技巧
		栈帧地址随机化是地址空间布局随机化(Address space layout randomization,ASLR)的一种,它实现了栈帧起始地址一定程度上的随机化,令攻击者难以猜测需要攻击位置的地址. ... 
- 深入剖析Linux IO原理和几种零拷贝机制的实现
		深入剖析Linux IO原理和几种零拷贝机制的实现 来源 https://zhuanlan.zhihu.com/p/83398714 零壹技术栈 公众号[零壹技术栈] 前言 零拷贝(Zero ... 
- js数组去重几种思路
		在一些后台语言中都内置了一些方法来处理数组或集合中重复的数据.但是js中并没有类似的方法,网上已经有一些方法,但是不够详细.部分代码来源于网络.个人总计如下:大致有4种思路 1)使用两次循环比较原始的 ... 
- 14.3.5.2 Deadlock Detection and Rollback  死锁检测和回滚:
		14.3.5.2 Deadlock Detection and Rollback 死锁检测和回滚: InnoDB 自动检查四艘,回滚一个事务或者事务来打破死锁. InnoDB 试图选择小的事务来回滚, ... 
- Linux - 死锁现象
		一.死锁的概念: 1.死锁的现象描述: 在很多应用中,需要一个进程排他性的访问若干种资源而不是一种.例如,两个进程准备分别将扫描的文档记录到CD上.进程A请求使用扫描仪, 并被授权使用.但进程B首先请 ... 
随机推荐
- 细聊分布式ID生成方法
			细聊分布式ID生成方法 https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=403837240&idx=1&sn=ae9 ... 
- Android PickerView滚动选择器的使用方法
			手机里设置闹钟需要选择时间,那个选择时间的控件就是滚动选择器,前几天用手机刷了MIUI,发现自带的那个时间选择器效果挺好看的,于是就自己仿写了一个,权当练手.先来看效果: 效果还行吧?实现思路就是自定 ... 
- tomcat启动出现PermGen space错误
			今天部署项目时,出现了jvm内存溢出的问题,显示PermGen space错误. 经过不断的努力,终于解决出来了. 步骤如下: 在eclipse中菜单栏run-->RunConfigurati ... 
- 采用EaglePHP框架解决分布式集群服务器利用MEMCACHE方式共享SESSION数据的问题
			一.问题起源 稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网 站,用户系统是统一的,即一套用户名.密码在整个网站的各个模块中都是可以登录 ... 
- Flask服务入门案例
			安装 pip install Flask 入门例子 from flask import Flask app = Flask(__name__) @app.route('/hello.world') d ... 
- Oracle SQLserver数据库创建表ID字段的自动递增_序列
			Oracle 将表t_uaer的字段ID设置为自增:(用序列sequence的方法来实现) ----创建表 Create table t_user( Id ),userid ),loginpasswo ... 
- 读取plist
			- (NSArray *)imageData { if (_imageData == nil) { // 从未初始化 // 初始化数据 // File : 全路径 // NSBundle : 一个NS ... 
- Java Servlet(一):创建工程(jdk7+tomcat7+eclipse)
			本篇文件主要记录下怎么在jdk7+tomcat7下,使用eclipse创建并运行一个servlet工程. 安装具体步骤从网上搜索就可以找到,这里不再赘述. 在eclipse中切换到j2ee下, 从导航 ... 
- .net 调度器怎么实现心跳(socket除了他,没选择吧)
			自己写调度器,就要从tcp通信入手:心跳的实现除了使用socket,想不到其他任何方案. socket基本使用demo: Socket Client: static void Main(string[ ... 
- Xcode 遇到 App Transport Security has blocked a cleartext HTTP 错误
			今天用Xcode 创建新项目用到 URL 发送请求时,报下面的错: “App Transport Security has blocked a cleartext HTTP (http://) re ... 
