前言
死锁避免算法大部分小伙伴应该都能说出来 “银行家算法”,死锁检测算法确实不常问也不常见,最近在一篇 Bilibili 的三面面经中看见了死锁检测算法,遂写出此文。
图片
死锁检测模型
在并发系统中,多个进程可能会因为资源竞争而陷入死锁。死锁检测模型提供了一种机制,通过将系统状态抽象为资源分配图,来识别死锁的存在。在这个图中,每个进程和资源都被表示为节点,资源和进程之间的有向边表示资源的分配和请求。
可证明结论:
- 无环安全状态:如果资源分配图是一个无环图,系统处于安全状态,因为存在一种资源分配序列可以使得所有进程顺利完成。
图片
- 环存在不确定性:如果图中存在环,系统处于不安全状态,但不一定处于死锁状态
图片
当每种资源类型只有一个实例时,死锁一定发生
如果资源类型有多个实例,系统也可能通过资源的动态分配来避免死锁
每种资源类型一个实例
图片
上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。
图 a 可以抽取出环,如图 b,它满足了环路等待条件,因此一定会发生死锁。
每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁的发生。具体算法描述如下:
- 初始化:创建一个资源分配图,用有向边表示资源和进程之间的关系。
- 深度优先搜索(DFS):从任意一个进程开始,进行深度优先搜索。
- 标记访问:在搜索过程中,对访问过的节点(进程)进行标记。
- 检测环:如果在搜索中遇到了已经被标记的节点,说明存在环,即检测到死锁。
详细算法步骤:
- 选择一个未访问的进程作为起点。
- 进行DFS,访问其相邻的资源节点。
- 标记该进程为已访问。
- 如果从该进程出发可以回到任何已标记的进程,则存在死锁。
- 如果所有进程都被访问且没有形成环,则没有死锁。
每种资源类型多个实例
图片
上图中,有三个进程四个资源,每个数据代表的含义如下:
- E 向量:资源总量
- A 向量:资源剩余量
- C 矩阵:每个进程所拥有的资源数量,每一行都代表一个进程拥有资源的数量(P1、P2、P3 三个进程)
- R 矩阵:每个进程请求的资源数量
进程 P1 和 P2 所请求的资源都得不到满足,只有进程 P3 可以,因此我们让 P3 先执行,之后释放 P3 拥有的资源,此时 A = (2 2 2 0)。这样的话 P2 就可以执行了,执行后释放 P2 拥有的资源,A = (4 2 2 1) 。P1 也可以执行了。所有的进程都可以顺利执行,所以没有死锁。具体算法描述如下:
- 初始化:定义E(资源总量)、A(资源剩余量)、C(进程拥有的资源矩阵)和R(进程请求的资源矩阵)。
- 寻找可执行进程:选择一个请求资源不超过A的进程执行。
- 资源分配:将该进程请求的资源分配给它,并更新A和C。
- 进程完成:当进程执行完毕后,将其拥有的资源释放回A,并更新C。如果所有线程都可以顺利执行完毕,则没有死锁
详细算法步骤:
- 标记所有进程为未标记。
- 从所有未标记的进程中选择一个,其请求的资源向量Ri小于等于A。
- 将该进程的资源需求从A中减去,并更新C矩阵,标记该进程为已执行。
- 如果没有这样的进程,检查是否有任何进程可以执行。如果没有,则检测到死锁
- 重复步骤2和3,直到所有进程都被标记为已执行或检测到死锁
总结
总结下:
- 对于每种资源类型一个实例的场景,若有环则必死锁;其死锁检测算法基于图论中的环检测技术,将死锁检测问题转化为有向图中的环判断问题
- 对于没中资源类型多个实例的场景,有环不一定死锁;其死锁检测算法通过模拟资源分配和回收过程,检测是否存在一系列进程可以顺利获取资源完成执行,从而判断系统是否处于死锁状态