操作系统处理进程死锁的类型大体可分为两类:第一类是不让死锁发生,第二类是检测死锁是否发生,包括以下几点
- 死锁预防
- 死锁避免
- 检查与解除死锁
- 忽略死锁
死锁预防
使死锁的四个条件不成立
-
互斥条件
- 任意时刻一个资源只能给一个进程使用,其他进程只能待定资源被释放
-
不可剥夺条件
- 进程所获得的资源在未使用完毕之前不能被其他进程强行剥夺
-
请求和保持
- 进程先申请它所需要的一部分资源,得到后再申请新的资源,在申请新资源的同时继续占有已分配的资源
-
循环等待
- 死锁发生时比如存在一个进程等待队列,它们形成一个环路,环路中每个进程已占有的资源同时被另一个进程所申请。
死锁预防就是破坏四个条件中任意一个条件,其基本思想时防患于未然,其中打破2、3、4时一种保证系统不进入死锁的静态分配策略。
破坏互斥条件:的方式是增加资源数量,然而这种方式代价高昂,而且资源数量有限和互斥使用时资源的固有特性。
破坏不可剥夺资源条件:不能立即得到申请的资源而等待的进程,其所申请的资源可以被全部剥夺。具体实现如下:
- 若一个进程已占用了某些资源,又要申请一个新的资源,在申请新的资源时,不能立即得到满足,在变为等待状态之前必须先释放已占有的所有资源,即阻塞前释放资源。
- 若一个进程申请某些资源,首先检查这些资源是否可以使用,如果可以则分配,如果资源已经被其他正在等待的进程占用,则剥夺所需资源,分配给这个进程。如果资源没有被正在等待的进程所占有,则该进程必须等待,在等待的过程中该进程也可能被剥夺资源。
该方法适用于状态容易恢复和保持的资源,如处理器、内存。同时该方法代价较大,一个进程在执行一段时间后被强行剥夺,会造成前阶段的工作失效。在极端环境下某个进程可能反复申请和是否资源,执行被无限推迟;增加系统开销,延长了进程周转时间,降低系统的吞吐量和性能。
破坏请求和保持条件:在进程开始执行前需要请求所有需要的资源。在执行过程中不能再请求资源。该方法简单安全容易实施,但降低了资源利用率。另外进程获得所有资源才能开始运行,但由于有些进程长期占用资源,可能导致其他进程推迟甚至得不到运行。
还有个问题是大部分进程进行开始时不能确定所需要的全部资源,其解决方案如下:
当进程没有占用资源才能允许它去申请新的资源
破坏循环等待条件:资源的有序分配策略,其基本思想是给所有资源顺序编号,较为紧缺的资源的编号较大。进程申请时,必须严格按照资源的顺序进行。否之不予分配,例如进程必须先申请小编号的资源才能申请大编号的资源。资源释放应该按递减的顺序进行。
哲学家就此问题就采用了资源有序分配策略
死锁的避免
死锁的预防以严格的方式防止死锁的发生,而牺牲了系统的性能。死锁的避免以获得较满意的系统性能,而且避免死锁发生的方法。
概念
系统对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据结果决定是否分配资源;如果分配后系统可能发生死锁则不予分配。
预防和避免的区别在于预防是通过破获四个必要条件,严格的限制死锁的发生。而死锁的避免没有那么严格限制死锁的必要条件,即使必要条件存在死锁也不一定发生。
死锁预防:死锁可能发生时就进行干预
死锁避免:避免死锁的最终发生
安全状态与安全序列
在资源分配之前先分析资源分配的安全性。
是否处于安全状态,其标准为是否能找到安全序列。安全序列是系统能够以一个序列依次执行完所有进程。其基本步骤是找到一个能够满足最大需求的进程,将资源分配给它。当它允许完毕后将释放的资源分配给另一个能够满足最大需求的进程,重复步骤直到执行完所有进程。而这些进程执行的次序就是安全序列。能够找到安全序列则说明当前处于安全状态,可以避免死锁。
银行家算法
将资源分配问题类比做银行家利用资金贷款的问题
银行家贷款给顾客:资源分配给进程
银行家可以安全收回贷款:进程执行完毕释放资源
规则如下:
- 当一个顾客对资金的最大需求不超过银行家现有的资金时就可接纳该顾客(现有资源大于进程最大需求量)
- *顾客可以分期贷款,但贷款的总数不能超过最大需求量
- *银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可以推迟支付,但总能使顾客在限有时间内得到贷款
- 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有资金
重点在于在每次进程请求资源使都需要判断当前资源的剩余数量是否满足该进程尚需要的最大需求量。这样可以保证始终可以至少有一个进程能够最终执行完毕,并释放资源
什么叫尚需要的最大需求量例如:一个进程占:5个;还需:5个,当前申请:2个。如果目前剩余资源为3个则不予分配,因为该进程还需要5个资源才能满足。如果剩余6个则可以分配5<6。就是说尚需要既不是进程总共需要也不是进程目前需要而是进程还需要的数量能够执行完毕。
死锁的检测和解除
系统为进程分配资源时,不考虑采取任何的措施来死锁避免和死锁预防,本着提高系统性能和资源利用率。并且在进行运行时不断地监督进程的执行和对资源的占用状态,判定死锁是否真的发生;一但死锁发送就采取专门的措施解除死锁,并且以最小的代价使整个系统恢复正常,这就是死锁检测和解除。
死锁检测的时机
死锁检测程序→检查是否存在死锁→恰当的死锁解除措施
- 在任何一次资源分配后
- 每次调度后
- 利用定时器定时运行检测
- 系统中某个进程位于阻塞状态或阻塞进程过多时,启动死锁检测程序
死锁检测算法
- 给进程和资源分配唯一编号
- 一张资源分配表包括:资源号和占有该进程的进程号
- 一张进程等待分配表包括:进程号和该进程所等待的资源号
- 算法规则:进程Pi申请一个以及被其他进程占用的资源Ri时,进行死锁检测。检测算法通过反复查找资源分配表和进程等待表,来确定进程Pi对资源Ri的请求是否导致形成环路,若是,便确定出现死锁。
死锁的解除方法
检测到死锁后一般来说只需要让一个或多个进程释放掉资源就可解除死锁。死锁解除后,释放资源的进程应恢复到原来的状态,才能保证进程的执行不会出现错误。因此,死锁解除实质上就是如何让释放资源的进程能够得到运行
为了解除死锁就需要剥夺资源,即需要考虑以下问题:
-
选择一个牺牲进程,即要确定剥夺哪个进程的哪些资源。
-
重新运行或回退到某一点开始继续运行
-
如何保证不发生“饿死”现象,即同一进程总是被剥夺
-
“最小代价”,进程回退带来的开销最小。重新启动进程的开销包括许多因素
- 进程的优先级
- 进程已经运行了多长时间,还需要多长时间
- 该进程使用的资源种类和数量?这些资源能简单地剥夺吗
- 还有多少进程要被撤销
- 该进程被重新启动运行地次数
死锁解除地方法:
1. 资源剥夺
挂起/激活一些进程,剥夺它们占有地资源给死锁进程,以解除死锁,待以后条件满足时,再激活被挂起地进程。
为了安全地释放资源,被剥夺资源的额进程必须返回到分配资源前地某一点。
- 还原算法,即恢复计算结果和状态
- 建立检查点主要时用来恢复分配前地状态。这种方法对实时系统和长时间运行地数据处理来说是一种常用地技术。在实时系统中,经常在某些程序地址插入检查地程序段,即采用检查点地的技术来验证系统的正确性,如发生故障,可从检查点重新启动。因此在有些系统中一但发生死锁,可以在释放某进程的资源后,从检查点重新启动。
2. 撤销进程
撤销死锁进程,将占有资源分配给另一些死锁进程,直到死锁解除。
全部撤销或逐个撤销,每次撤销都需要运行检查程序,如果还存在死锁则继续撤销。极端情况下可能导致只剩一个照成死锁的进程。
采用什么方法可以代价最小:
- 进程优先数,被撤销进程的优先数
- 进程类的外部代价,不同类型的进程规定出各自撤销的代价
- 运行代价,即重新启动进程并运行到当前撤销点所需要的代价。
资源分配图
图中p1->r2->p2->r1->p1且r1和r2都只有一个资源实例因此环形成了死锁
资源分配图简化
现在r2有两个资源,对其进行简化。
- 找到一个既非孤立又可以获得所有资源的进程图中只有p3
- p3已经获得了所有的资源,在执行结束后会释放所有资源,因此可以将r2->p3、r3->p3的分配边擦去,使其成为孤立点。
- 可将r2的空闲资源分配给向r2发出资源申请的p1,在图中表示为将p1->r2的申请边改为p1<-r2分配边。
重复以上三个步骤查看最终是否可以完全简化即将所有进程都置为孤立点,否则说明存在死锁。任何简化的顺序最终得到的简化图是相同的。
死锁定理
判断死锁的方法,死锁定理
- 如果资源分配图中没有环路,则系统没有死锁
- 如果资源分配图中出现了环路,则系统中可能存在死锁。
如果处于环路的每个资源类中均只包含1个资源实例,则环路的存在即意味着死锁的存在。环路是死锁的充分必要条件
环路 —> 死锁
环路 <— 死锁
如果处于环路的每个资源类中实例个数不全为1,则环路是死锁的必要条件而不是充分条件。
环路 -/→ 死锁
环路 <— 死锁