一、死锁特征
1. 定义
一组进程中,每个进程都无限等待被该组进程中另一进程所占有的资源,因而永远无法得到的资源,这种现象称为进程死锁,这一组进程就称为死锁进程。
2. 出现死锁的四个必要条件
- 互斥:任何时刻只能由一个进程使用一个资源实例
- 持有并等待:进程保持至少一个资源,并正在等待获取其他进程持有的资源
- 非抢占:资源只能在进程使用后自愿释放
- 循环等待:存在等待进程集合{P0,P1,...,PN},P0正在等待P1所占用的资源,P1正在等待P2占用的资源,...,PN-1正在等待PN所占用资源,PN正在等待P0所占用资源。
注:这四个条件同时存在并不一定是死锁,而死锁一定满足这四个条件。
二、死锁处理办法
目前处理死锁的方法可以归纳为如下:
(1)不考虑此问题(鸵鸟算法):把头埋在沙子里,假装根本没发生问题。因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。
(2)不让死锁发生,分为以下两种:
- 死锁预防:不让死锁发生的静态策略,通过设计合适的资源分配算法,由资源分配策略保证不让死锁发生
- 死锁避免:不让死锁发生的动态策略,以不让死锁发生为目标,跟踪并评估资源分配过程,根据评估结果决策是否分配
(3)让死锁发生
通过死锁的检测判断死锁是否真的发生,然后采用一些方法来解除死锁的问题。
总体解决锁死发生的方法可以分为四类:鸵鸟算法、死锁预防、死锁避免以及死锁检测与解除。
三、死锁预防和死锁避免
1. 死锁预防:限制申请方式
预防是采用某种策略,限制并发进程对资源的请求,使系统在任何时刻都不满足死锁的四个必要条件。
(1) 破坏“互斥使用/资源独占”条件
资源本身的特性是独占的,是排他性使用的,所以要使用一种资源转换技术,把独占资源变为共享资源。例如针对于打印机,SPOOLing技术的引入解决不允许任何进程直接占有打印机的问题。设计一个“守护进程/线程”负责管理打印机,进程需要打印时,将请求发给该daemon,由它完成打印任务。
(2) 破坏“占有且等待”条件
指一个进程占有了一部分资源,在申请其他资源的时候由于得不到满足而进入等待状态。有下面两种方案实现:
- 实现方案1:要求每个进程在运行前必须一次性申请它所要求的所有资源,且仅当该进程所要资源均可满足时才给予一次性分配。这种实现会使得资源的利用率很低,当一个进程所需要的资源不能同时满足的情况下可能一直处于等待状态,会产生饥饿现象。
- 实现方案2:在允许进程动态申请资源前提下规定,一个进程在申请新的资源不能立即得到满足而变为等待状态之前,必须释放已占有的全部资源,若需要再重新申请。
(3) 破坏“不可抢占”条件
实现方案是当一个进程申请的资源被其他进程占用时,可以通过操作系统抢占这一资源(两个进程优先级不同)。这种方法具有局限性,适用于状态易于保存和恢复的资源,如CPU、内存资源。
(4) 破坏“循环等待”条件
主要思想是通过定义资源类型的线性顺序实现,实现方案是资源有序分配法,把系统中所有资源编号,进程在申请资源时必须严格按资源编号的递增次序进行,否则操作系统不予分配。实现资源的有序分配时需要考虑如何对资源进行编号,通常可以利用资源使用的频繁性进行排序。
假如有P1,P2…Pn共n个进程,每个进程都需要一定的资源,一定可以找到某个进程所需要申请的资源的序号是最大的这个进程,从这个进程开始执行;这个进程执行完之后再继续找下一个所需要资源序号最大的进程,以此类推,因此使用资源的有序分配法一定可以解决死锁问题。
2. 死锁避免
利用额外的先验信息,在分配资源时判断是否会出现死锁,只在不会死锁时分配资源。
- 要求进程声明需要资源的最大数目
- 限定提供与分配资源数量,确保满足进程的最大需求
- 动态检查的资源分配状态,确保不会出现环形等待
3.系统资源分配的安全状态
当进程请求资源时,系统判断分配后是否处于安全状态。
安全状态:针对所有已占用进程,存在安全序列
安全序列:
序列<P1,P2,...,PN>是安全的
- Pi要求的资源 ≤ 当前可用资源 + 所有Pj 持有资源,其中 j < i
- 如 Pi 的资源请求不能立即分配,则 Pi 等待所有 Pj ( j < i )完成
- Pi完成后,Pi+1可得到所需资源,执行并释放所分配的资源
- 最终整个序列的所有Pi都能获得所需资源
安全状态与死锁的关系:
系统处于安全状态,一定没有死锁,系统处于不安全状态,可能出现死锁,避免死锁就是确保系统不会进入不安全状态
四、银行家算法
1. 银行家算法是仿照银行发放贷款时采取的控制方式而设计的一种死锁避免算法,起这样的名字是因为该算法原本是为银行系统设计的,以确保银行在发放贷款时,不会发生不满足客户需要的情况,在操作系统中也可以用它来避免死锁。
为实现银行家算法,每一个进程进入系统时,他它须申明在运行过程中,可能需要每种资源类型的最大数目,其数目不能超过系统所拥有的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程。若有,再进一步计算在将这资源分配给进程后,是否会使系统处于不安全状态。如果不会,才将资源分配给它,否则让进程等待。
应用条件如下:
- 在固定数量的进程中共享数量固定的资源
- 每个进程预先指定完成工作所需的最大资源数量
- 进程不能申请比系统中可用资源总数还多的资源
- 进程等待资源的时间是有限的
- 如果系统满足了进程对资源的最大需求,那么,进程应该在有限的时间内使用资源,然后归还给系统
2. 银行家算法数据结构
n = 进程数量,m = 资源类型数量
- Max (总需求量) : n×m 矩阵,如果Max[ i, j ] = k,表示进程Pi最多请求资源类型 Rj 的 k 个实例。
- Available (剩余空闲量) :长度为m的向量,如果Available[ j ] = k,则有 k 个类型 Rj 的资源实例可用。
- Allocation (已分配量):n×m 矩阵,如果Allocation[ i, j] = k,则 Pi 当前分配了 k 个 Rj 的实例。
- Need (未来需要量):n×m 矩阵,如果Need[ i, j ] = k,则Pi可能需要至少k个Rj实例完成任务。
- Need[ i, j ] = Max[ i, j ] - Available[ i, j ]
3. 安全状态判断
4. 银行家算法
5. 银行家算法的安全状态判断示例
四、死锁检测
1. 死锁检测与解除:允许死锁发生,但是操作系统会不断监视系统进展情况,判断死锁是否真的发生;一旦死锁发生则采取专门的措施,解除死锁并以最小的代价恢复操作系统运行。
检测死锁是否发生有三个典型的检测时机:
(1)当进程由于资源请求不满足而等待时检测死锁,缺点是系统开销大;
(2)定时检测;
(3)系统资源利用率下降时检测死锁。
2. 死锁检测算法的数据结构
- Available:长度为m的向量,每种类型可用资源的数量。
- Allocation:一个 n×m 的矩阵,当前分配给各个进程每种类型资源的数量,进程Pi 拥有资源Rj 的Allocation[ i,j ]个实例
3.死锁检测算法
4. 死锁检测实例
5. 死锁检测算法的使用
(1)死锁检测的时间和周期选择依据
- 死锁多久可能会发生
- 多少进程需要被回滚
(2)资源图可能有多个循环
- 难于分辨“造成”死锁的关键进程
五、死锁恢复
1. 进程终止
(1)终止所有的死锁进程,代价较大;
(2)按照某种原则逐一撤消死锁进程,直到没有死锁;
(3)终止进程的顺序应该根据:
- 进程的优先级
- 进程已运行时间以及还需运行时间
- 进程已占用资源
- 进程完成需要的资源
- 终止进程数目
- 进程是交互还是批处理
2. 资源抢占
(1)从陷于死锁的进程中逐个强迫放弃所占用的资源,直至死锁消失;
(2)从另外的进程那里强行剥夺足够数量的资源分配给死锁进程,以解除死锁状态。