一. 死锁概述
1.1 资源问题
1.1.1 可重用性资源和消耗性资源
- 可重用性资源: 可供用户重复使用多次的资源,具有如下性质
- 每个可重用性资源中的单元职能分配给一个进程使用,不允许多个进程共享
- 进程在使用可重用性资源时,必须按照以下顺序
1. 请求资源:如果请求资源失败,请求进程会被阻塞或循环等待
2. 使用资源:进程对资源进行操作
3. 释放资源:当进程使用完后自己释放资源
- 可消耗性资源: 又叫临时资源,它是在运行期间,由进程动态的创建和消耗的,具有如下性质
- 每一类可消耗性资源的单元数目在进程运行期间是可以不断变化的
- 进程在运行过程中,可以不断的创造可消耗性资源的单元,将它们放入资源类的缓冲区中
- 进程在运行过程中,可以请求若干个可消耗性资源单元,用于自己的消耗,不再将它们返回给该资源类中
1.1.2 可抢占性资源和不可抢占性资源
- 可抢占性资源:指进程获得这类资源后,该资源又可以被其他的进程或系统抢占。如优先级高的进程可以抢占优先级低的进程的处理机,又可以把一个进程总一个存储区转移到另一个存储区,在内存区紧张时,还可以将一个进程从内存调出到外存上,即抢占该进程在内存的空间。可见CPU和主存均属于可抢占性资源,对于这类资源是不会引起死锁的
- **不可抢占性资源:**一旦进程把某资源分配给该进程后,就不能将它强行收回,只能在进程用完后自行释放,如录制的光盘,磁带机,打印机等
1.2 计算机系统中的死锁
死锁的起因,通常是源于多个进程对资源的争夺,不仅对不可抢占资源进行争夺时会引起死锁,而且对可消耗资源进行争夺时,也会引起死锁
1.2.1 竞争不可抢占性资源引起死锁
如系统中有两个进程P1和P2,它们都准备写两个文件F1和F2,这两者都属于可重用和不可抢占性资源,此时P1会先打开F1,再打开F2,而P2会先打开F2,再打开F1,就可能会造成死锁
此时P1 会等待P2释放F2,而P2 会等待P1释放F1
1.2.2 竞争可消耗资源引起死锁
- 如上,有 P1,P2,P3,三个进程,M1,M2,M3,三个可消耗资源。以P1为例子,它会生产M1给P2,又会从P3处获得M3
- 假设程序通信顺序是一下方式,则不会造成死锁
- 但若是以下方式,则可能产生死锁,即三方同时等待上一家的资源,却没有一方生产
1.2.3 进程推进顺序不恰当引起死锁
有两个进程P1,P2,两个资源R1,R2
- 进程推进顺序合法,如果按照以下顺序,程序可合法进行
1. P1 Request:R1
2. P1 Request:R2
3. P1 Release:R1
4. P1 Release:R2
5. P2 Request:R1
6. P2 Request:R2
- 1.3.2 进程推进顺序不合法,如果按照以下顺序,则百分百死锁
1. P1 Request:R1
2. P2 Request:R2
3. P1 Request:R2
4. P2 Request:R1
此时两个进程都阻塞住,等待另一个释放资源,阻塞再3,4步
1.3 死锁的定义、必要条件和处理方法
1.3.1 死锁的定义
如果一组进程中的每一个进程都在等待由该进程组中的其他进程才能引发的事件,那么该组进程是死锁
1.3.2 产生死锁的必要条件
- 死锁要想产生,下面4个条件缺一不可
- 互斥条件:进程对分配到的资源进行排它性使用,即在一段时间内某资源只能被一个进程占用,如果其他进程请求该资源的话只能阻塞等待
- 请求和保持:进程已经保持了至少一个资源,但又提出了新的资源请求
- 不可抢占条件:进程以获得的资源在未使用完之前不能被抢占,只能在进程使用完时自己释放
- 循环等待条件:发生死锁时,必然存在一个进程-资源的循环链。即进程集合{P0,P1,P2,…Pn}中P0在等待一个P1占用的资源…Pn在等待一个P0占用的资源
1.3.3 处理死锁的方法
- 目前处理死锁的方法可以归结为以下四种
- 预防死锁:一种比较简单和直观的事先预防方法,通过设置某些限制条件去破坏产生死锁四个必要条件中的一个或几个来预防死锁,比较容易实现,且已广泛使用
- 避免死锁:同样是事先预防策略,不过不是通过破坏产生死锁的四个必要条件,而是用某种方法防止系统进入不安全状态
- 检测死锁:这种方法无须实现采用任何限制措施,而是允许进程在运行过程中发生死锁,可通过检测机构及时的检测出死锁的发生,然后采取恰当措施,把进程从思索中解脱出来
- 解除死锁:当检测到系统中已发生死锁时,就采取相应措施,将进程从死锁状态中解脱出来,常用方法是撤销一些进程,回收它们的资源
二. 预防死锁
预防死锁的方法是通过破坏产生死锁的四个必要条件中的一个或几个,以避免发生死锁,由于互斥条件是非共享设备所必须的,不仅不能改变,还应加以保证,因此,主要还是破坏产生死锁的后三个条件
2.1 破环“请求和保持条件”
为了能破坏该条件,系统必须保证做到:当一个进程在请求资源时,它不能持有不可抢占资源。该保证可通过如下两个不同的协议实现:
2.1.1 第一种协议
- 该协议规定,所有进程在开始运行之前,必须一次性申请其在整个运行过程中所需要的全部资源。此时若系统有足够的资源分配给某进程,便可把其需要的所有资源分配给它。这样,该进程在整个运行期间,便不会再提出资源要求
- 该协议的优点是简单、易行且安全,但有以下几个明显的缺点:
- 资源被严重浪费,严重的恶化了资源的利用率,进程在开始运行时就一次性的占用了整个运行过程所需的全部资源,其中有些资源可能仅在运行初期或运行快结束时才使用,甚至根本不用
- 进程经常会发生饥饿现象,仅当进程在获得了其所需的全部资源后才能开始运行,这样就可能由于个别资源长期被其他进程占用,而导致等待该资源的进程迟迟不能运行
2.1.2 第二种协议
- 该协议是对第一种协议的改进,它允许一个进程只获得运行初期所需的资源后,便开始运行,进程运行过程中再逐步释放已分配给自己的,且已用完的资源。然后再请求新的所需资源
- 第二种协议不仅能使进程更快的完成任务,提高设备的利用率,还可以减少进程发生饥饿的几率
2.2 破坏“不可抢占条件”
- 为了能破坏“不可抢占条件”,协议中规定,当一个保持了某些不可被抢占资源的进程,提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请
- 该方法实现起来比较复杂,而且需付出很大的代价。这种策略可能会导致前一阶段的工作失效,还可能因为反复的申请和释放资源致使进程的执行被无限的推迟。这不仅延长了进程的周转时间,而且也增加了系统的开销,降低系统吞吐量
2.3 破坏“循环等待条件”
- 一个能保证“循环等待”条件不成立的方法是,对系统所有资源类型进行线性排序,并赋予不同的序号。设R = (R1,R2,R3,……Rm)为资源类型的集合,如系统中的磁盘驱动器F(1)、硬盘驱动器F(5)、打印机F(12)
- 采用这样的预防协议: 规定每个进程必须按序号的递增顺序请求资源。一个进程在开始时,可以请求某类资源Ri,以后,当且仅当F(Rj)>F(Ri)时,进程才可以请求资源Rj的资源,如果需要多个同类资源单元,则必须一起请求
- 这种预防死锁的策略与前两种策略相比,其利用率和系统吞吐量都有较明显的改善,但还存在以下问题:
- 为系统中各类资源所规定的序号必须相对稳定,这限制了新类型设备的增加
- 其次,尽管在为资源的类型分配序号时,已经考虑到大多数作业在实际使用这些资源时的顺序,但还是会发生这种情况:作业使用各类资源的顺序与系统规定的顺序不同,造成对资源的浪费
- 这种按规定次序申请资源的方法必然会限制用户简单、自主的编程
三. 避免死锁
3.1 系统安全状态
在死锁避免方法中,把系统的状态分为安全状态和不安全状态。当系统处于安全状态时,可避免发生死锁,反之,当系统处于不安全状态时,则可能进入到死锁状态
3.1.1 安全状态
- 在该方法中,允许进程动态的申请资源,但系统在进行资源分配之前,应先计算此次资源分配的安全性,若此次分配不会导致系统进入不安全状态,才可将资源分配给进程
- **安全状态:**当系统能按照某种进程推进顺序(P1,P2,…Pn)为每个进程Pi分配其所需资源,直至满足每个进程对资源的最大需求
3.1.2 安全状态例子
**此时系统处于安全状态:**存在 P2 -> P1 -> P3,只要系统按此进程序列分配资源,就可以使每个进程都顺利完成
3.1.3 安全状态向不安全状态的转换
- 在建立了系统安全状态的概念后,就可以知道避免死锁的基本思想,即确保系统处于安全状态
- 如果不按照安全序列分配资源,则系统可能会由安全状态进入不安全状态
3.2 利用银行家算法避免死锁
- 每一个新进程在进入系统时,它必须声明在运行过程中可能需要每种资源类型的最大资源数目,其数目不应该超过系统所拥有的资源总量
- 当进程请求一组资源的时候,系统必须首先确定是否有足够的资源分配给该进程,若有,再进一步计算在将这些资源分诶给进程后,是否会使系统处于不安全状态,如果不会,才将资源分配给他
3.2.1 银行家算法中的数据结构(P111)
3.2.2 银行家算法
3.2.3 安全性算法
3.2.4 银行家算法之例
四. 死锁的检测和解除
如果在系统中,既不采取死锁预防措施,也未配有死锁避免算法,系统很可能会发生死锁,这时系统应当提供两个算法
- 死锁检测算法:用于检测系统状态,已确定系统中是否发生了死锁
- 死锁解除算法:当认定系统中已发生了死锁,利用该算法可将系统从死锁状态中解除
4.1 死锁的检测
为了检测死锁,系统中必须:
- 保存有关资源的请求和分配信息
- 提供一种算法,利用这些信息来检测系统是否进入死锁状态
4.1.1 资源分配图(P115)
P表示进程,R表示资源及其数量
- P1 拥有两个 R1,同时申请一个R2
- P2 拥有一个 R1 和一个 R2,同时申请一个R1
4.1.2 死锁定理
- 在资源分配图中,找出一个既不阻塞,又非独立的节点 Pi,在顺利的情况下,Pi可获得所需资源而继续运行,直至运行完毕,再释放其全部资源,这相当于消去Pi的请求边和分配边
- P1释放资源后,便可使P2获得资源而继续运行,直到P2完成后又释放出它所占的全部资源
- 在进行一系列的简化后如果能消去图中的所有边,使所有的进程节点都成为孤立节点,则称该图是可完全简化的,若不能通过任何过程使图完全简化,则称该图是不可简化的
4.1.3 死锁检测中的数据结构
死锁检测中的数据结构类似于银行家算法中的数据结构
五. 死锁的解除
如果利用死锁检测算法检测出系统中已发生了死锁,则应立即采取相应的措施,以解除死锁,通常采用解除死锁的两种方法是:
- 抢占资源:从一个进程或者多个进程中抢占足够数量的资源,分配给死锁进程,以解除死锁状态
- 终止进程:终止(或撤销)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态中解除
5.1 终止进程的方法
- 终止所有死锁进程
- 逐个终止进程:按照某种顺序,逐个的终止进程,直到有足够的资源,以打破循环等待,把系统从死状态解脱出来为止,通常考虑以下几个因素:
- 进程的优先级的大小
- 进程已执行了多少时间,还需要多少时间方能完成
- 进程在运行中使用资源的多少,以后还需要多少资源
- 进程的性质是交互式的还是批处理式的
5.2 付出代价最小的死锁解除算法
(P118)