死锁的必要条件
产生死锁的四个必要条件:
- 互斥: 一个资源一次只能分配给一个进程使用。
- 占有且等待: 一个进程在等待其他进程释放资源的同时,继续占有已经拥有的资源。
- 不可抢占: 一个进程不能强行占有其他进程已占有的资源。
- 循环等待:若干进程由于等待其他进程释放资源,而形成相互等待的循环。如进程A等待进程B,进程B等待进程C,•••,进程X等待进程Y,进程Y等待进程A。
如何检测死锁
(1)操作系统周期性地执行算法检测是有存在循环等待,如果存在,则对死锁进行恢复。
(2)可以利用资源分配图,检测有向图中是否存在环。如果存在环,表明死锁可能发生,采取措施进行恢复。
具体实现: 从一个节点出发进行深度优先搜索(DFS),对访问过的节点进行标记。如果访问了已经标记的节点,就表示有向图存在环,即检测到死锁的发生。
下面这个资源分配图存在环,并且死锁已经发生:
下面这个资源分配图存在环,但是死锁并没有发生(因为每种类型存在多个资源):
(3)使用死锁避免中的分配矩阵A和表示每种资源的剩余量的向量V,新添请求矩阵Q表示每个进程将要请求的资源数量。
- 首先标记矩阵A中全为0的行对应的进程。
- 查找下标i,要求进程Pi未被标记且矩阵Q中对应的行满足:Q i≤V,如果找不到这样的下标i,则终止算法。
- 找到下标i,将进程Pi已分配的资源加到V中,并标记进程Pi。重复步骤3和4。
- 算法终止时,如果存在未被标记的进程,说明存在死锁。
如何解决死锁问题
解决死锁的四种办法:鸵鸟策略、死锁预防、死锁避免、死锁恢复。(有些人把检测死锁也当成是解决死锁问题的方法)
鸵鸟策略
不采取任何措施,能获得更高的性能。死锁发生的概率很低,并且由于并发系统的不确定性,就算发生死锁对对用户的影响并不大,所以可以采用鸵鸟策略。大多数操作系统,包括Linux、Unix和Windows,解决死锁的办法仅仅是忽略它。
死锁预防
(1)破坏互斥
设置超时时间。
(2)破坏占有且等待
当一个进程占有某些资源并进一步申请其他资源时,如果遭到拒绝,该进程必须主动释放已经占有的资源。
(3)破坏不可抢占
在两个进程优先级不同的情况下,高优先级的进程申请被低优先级进程占有的资源时,系统要求低优先级的进程释放资源。
(4)破坏循环等待
给资源统一进行编号,进程只能按照编号顺序请求资源。
死锁避免
存在n个进程和m种资源,以下是死锁避免过程中相关的概念:
- 向量R,表示每种资源的总量(Resource)。
- 向量V,表示每种资源的剩余量(Available)。
- Claim矩阵,Cij表示进程 i 对资源 j 的需求。
- Allocation矩阵,Aij表示进程 i 已经分配到的资源 j 的数量。
(1)方法一:进程启动拒绝
如果一个进程的资源请求会导致死锁,则不启动该进程,具体操作如下:第n+1个进程对资源j的需求,应该满足:前n个进程的最大资源需求加上当第n+1个进程的资源需求,应该小于等于总资源量。
该方法很难是最优的,因为它总是假设最坏的情况: 所有的进程同时发出其最大资源请求。
(2)方法二:资源分配拒绝(银行家算法)
定义矩阵C − A,即矩阵C和矩阵A中对应位置的数值相减,记录进程对每种资源的剩余需求。
对于进程i,它对资源 j 增加的请求都满足:Cij − Aij≤Vij,即需要的量小于等于现存量。
- 安全状态:当进程发出增加资源的请求时,至少有一种资源分配序列不会导致死锁。即至少有一种资源分配序列,能保证所有的进程顺利运行直到结束。
- 不安全状态:不存在任何一种资源分配序列保证不会死锁。
如果一个进程增加资源的请求会导致死锁,则不允许此分配。举例:当进程P1、P2、P3都发起增加资源的请求时,可以先满足进程P2的资源请求;当进程P2运行结束后,释放资源,可用资源增加;接着满足进程P1的资源请求,最后满足进程P3的资源请求。
死锁恢复
死锁恢复的方法有:
- 取消所有死锁的进程。
- 把每个死锁的进程回滚到前面定义的某些检查点(checkpoint),重新启动所有进程。
- 连续取消死锁的进程直到不存在死锁。
- 连续抢占资源直到不存在死锁。
银行家算法
(1)银行家算法的数据结构
- 可利用资源向量(Available):系统还可以分配的资源
- 最大需求矩阵(Max):进程的最大资源需要
- 分配矩阵(Alloction):进程已经获得的资源
- 需求矩阵(Need):进程还需要获得的资源
(2)银行家算法流程
- 假设 P1 进程提出请求 K 个资源。
- 如果 K <= Need,就继续步骤;否则出错,因为请求资源 K 不能超过还需要获得的资源。
- 如果 K <= Available,就继续步骤;否则出错,因为请求资源 K 不能超过系统还可以分配的资源 Available。
- 系统试探分配资源,并修改下列数据 Available = Available - K;表示分配给 P1 K个资源后,还剩多少系统可分配资源 Allocation = Allocation + K;表示 P1 已经获得的资源 Need = Need - K;表示进程 P1 还需要获得的资源。
- 此时系统执行安全性算法,计算进程是否处于安全性状态。
(3)安全性算法
安全性算法是银行家算法在第五步执行的子算法,用于检查进程的安全状态。银行家算法是计算某一个进程对资源的需求问题,安全性算法是计算所有的进程在各自的银行家算法执行下,是否处于安全状态。
1)安全性算法中有两个向量
- 工作向量(Work):系统提供给进程的各类资源数目
- Finish:表示系统是否有足够的资源分配给进程,这是一个布尔值。初始化为 false。
2)算法描述
在进程集合中找到下述条件的进程:
- Finish[ i ] = false。
- Need <= Work。
- 进程执行完毕。
- Work = Work + Allocation。
- Finish [ i ] = true。
- 返回继续执行 1 ,寻找其他的进程分配资源。
- 若所有的 Finish 为 true 则安全。