一、概述

  • 上一篇讲述了“程序崩溃检测”功能,感兴趣同学可以 点击这里进行回顾。
  • 此篇我们开始设计第二功能模块“进程死锁监测”。
  • 这里借鉴了博主“程序喵大人”的设计思路,利用“gdb+python脚本”的方法监测死锁。

二、死锁

计算机系统中有很多一次只能由一个进程使用的资源,它们往往称作独占资源,如打印机、内部表单等。但许多进程往往需要访问的资源不止一个,假如有两个进程,各占有一个这样资源,然后交错申请对方持有的资源,这样就会出现因为无法获取全部资源而陷入无限期阻塞,这种状况就是死锁。
当计算机系统同时具备4个必要条件时,就会发生死锁:

  • 互斥条件: 独占资源在一段时间只能由一个进程独占,不能同时被两个及以上进程占有。必须等待占有该资源的进程主动释放它之后,其他进程才能占有该资源。
  • 占有且等待条件: 进程至少已经占有一个资源,但又申请新的资源,由于该资源已被占用,此时进程阻塞。但它们在等待新资源时,仍继续占有已分到的资源。
  • 不可抢占条件: 一个进程占有的资源用完之前,其他进程不能强行夺走该资源,只能由该进程用完之后主动释放。
  • 循环等待条件: 存在一个进程等待序列{p1,p2,…,pn},其中p1等待p2所占的某个资源,p2等待p3的某个资源,…,pn等待p1占用的某个资源,从而形成一个进程循环等待环。

而解除死锁,也只需要破坏上面的任何一个条件就可以了。

三、资源分配图

可以利用有向图的形式更精确地描述死锁,该图称为系统资源分配图。
该图由结对组成:G=(V,E)。V是顶点集合,E是边集合。顶点集合又分为进程集合P与系统资源集合R组成。p->r为申请边,r->p为赋给边。

  • 如果每类资源的实体只有一个,那么图中出现环路就说明死锁了,此为充要条件。
  • 如果每类资源实体的实体不止一个,则就算产生环路也不一定出现死锁,此为必要条件。

总得来说,如果资源分配图没有环路,则系统不会陷入死锁状态;如果存在环路,则有可能出现死锁,但不能确定。

Linux监控死锁命令 linux死锁检测_资源分配


Linux监控死锁命令 linux死锁检测_系统资源_02

四、死锁检测

有了上面的基本概念,我们判断死锁的方面也就明确了,即判断资源分配图中是否存在闭环,若有闭环再去查看具体锁信息,进而判断死锁情况。
利用gdb查看死锁信息:

$ gdb attach 进程pid
(gdb)info threads 查看进程线程情况

Linux监控死锁命令 linux死锁检测_Linux监控死锁命令_03

(gdb) thread id 进入具体线程

可以手动检查线程调用锁的情况。
deadlock.py的使用

(gdb)source -v ./deadlock.py
 (gdb) deadlock

Linux监控死锁命令 linux死锁检测_linux_04

五、思考

起初打算和上一个程序崩溃检测功能封装一起,做成守护进程的形式。但是我发现,我在实现过程中是基于gdb attach的方法,附着到正在运行的进程上。这会让attach也成为该进程的父进程,并隔绝所有信号,交于gdb先处理。这就会导致正在运行中的进程可能会有那么几毫秒甚至几秒时间无法收到外界信号,这对一些进程的影响是巨大的,所以只能退而求其次,选择将其封装成命令,在发现可能出现死锁的进程后,调用该命令来调试。