死锁定义:
在一组进程发生死锁的情况下,这组死锁进程中的每个进程,都在等待另一个死锁进程所占有的资源。但是这些进程都无法运行,因此它们谁也不能不能释放资源,致使没有一个任何一个进程可被唤醒。这样一组只能无限期地等待下去。
思考:产生死锁的两个根本原因与操作系统的两个基本特征(并发和共享)之间存在着什么样的联系?
产生死锁的必要条件:
(1)互斥条件:
资源只能被一个进程占用。如果还有其他进程请求该资源,则请求进程只能等待。
(2)请求和保持条件:
进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
(3)不可抢占条件:
进程已获得的资源在未使用完之前不能被抢占,只能在进程使用完时由自己释放。
(4)循环等待条件:
在发送死锁时,必然存在一个进程-资源的循环链,即进程集合{P0,P1,P2,...pn}中P0正在等待一个P1占用的资源,P1正在等待P2占用的资源,.....,pn正在等待已被P0占用的资源。
思考:为什么其中一个条件不满足,为什么不会产生死锁?
处理死锁的方法:预防死锁、避免死锁、检测死锁、解除死锁
预防死锁:
通过破坏死锁的四个必要条件。
由于互斥条件必须保证,所以主要破坏死锁的后三个必要条件。
破坏请求和保持条件:
第一种协议:
所有进程在开始运行之前,必须一次性地申请在整个运行过程中所需的全部资源。
(1)进程在整个运行期间,不会再提出资源要求,从而破坏了请求条件。
(2)只要有一种资源不能满足进程的要求,即使其他所需的各种资源都空闲也不分配给该进程。
由于进程在等待期间没有占用任何资源,破坏了保持条件。
优点:简单易行安全
缺点:
(1)严重浪费资源。
进程在开始运行时就一次性占用了整个运行过程所需的全部资源,有的资源只用一会。
(2)使进程经常发生饥饿现象
个别资源可能被进程占用很长时间,导致等待该资源的进程迟迟不能开始运行。
第二种协议:
对第一种协议的改进。
它允许一个进程只获得运行初期所需的资源后,便开始运行。
进程运行过程中再逐步释放已分配给自己的、且已用完的全部资源,然后再请求的资源。
用PV操作类比理解:
P(R1,R2)->V(R1,R2)->P(R3,R4)->V(R3,R4)...
优点:使进程更快地完成任务,提高设备的利用率,减少进程发生饥饿的几率。
破坏不可抢占条件:
当占有资源的进程提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源。
该方法实现起来比较复杂,且需很大的代价。
破坏循环等待条件:
其中一个方法是,对系统所有资源类型进行线性排序,并赋予不同的序号。在对系统所有资源类型进行线性排序后,便可规定每个进程必须按序号递增的顺序请求。
如果需要多个同类资源单元,则必须一起请求。
避免死锁:避免系统进入不安全状态
安全状态:
系统能按某种进程推进顺序(P1,P2,...,Pn)为每个进程Pi分配其所需的资源,直至满足每个进程对资源的最大需求,使每个进程都可顺利地完成。反之,处于不安全状态。
当系统进入不安全状态,有可能进入死锁状态。
< P2,P1,P3 >是一个安全序列。 所以该时刻是安全的。
如果不按照安全序列分配资源,则系统可能会由安全状态进入不安全状态。
如果分给P3,则系统进入不安全状态。
利用银行家算法避免死锁:
可利用资源向量Available:系统中资源的个数
一个长度为m的数组,如果Available[j]=k,则表示系统中现有Rj类资源k个。
最大需求矩阵max:
一个n*m矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。
如果MAX[i,j]=k,则表示进程i需要Rj类资源的最大数目为K。
分配矩阵Allocation:
一个n*m的矩阵,它定义了系统中每一类资源当前已分配每一进程的资源数。
如果Allocation[i,k]=k,则表示进程i当前已分得Rj类资源的数目为k
需求矩阵Need:
一个n*m的矩阵,用以表示每一个进程尚需的各类资源数。
如果Need[i,j]=k,则表示进程i还需要Rj类资源K个
MAX[i,j]=Need[i,j]+Allocation[i,j]
银行家算法:
设Requesti是进程Pi的请求向量,如果Requesti[j]=k,表示Pi需要K个Rj类型的资源。
安全性算法:
work=available,找满足条件的P,
work+allocation,改为true,继续找。如果找不到则不安全。
死锁的检测:
资源分配图:由一组结点N和一组边E组成的一个对偶G=(N,E)。
(1)可以把N分为两个互斥的子集,即一组进程结点P={P1,P2,P3,..,Pn}和一组资源结点R={R1,R2,...,Rn}。
N=P∪R
(2)对于e∈E,都连接着P中的一个结点和R中的一个结点。
e={Pi,Rj}是资源请求边,由进程Pi指向Rj,表示进程Pi请求一个单位Rj资源。
e={Rj,Pi}是资源分配边,由资源Rj指向Pi,表示一个单位的资源Rj分配给进程Pi。
死锁定理:
(1)在资源分配图中,找出一个既不阻塞又非独立的进程Pi。
在顺利的情况下,Pi可获得所需的资源而继续运行,直至运行完毕,再释放其所占有的全部资源,这相当于去Pi的请求边和分配边,使之成为孤立的结点。
(2)Pi释放资源后,便可使P2获得资源而继续运行,直至P2完成后又释放出它所占有的全部资源,
直至P2完成后又释放出它占有的资源,即P2的两条边请求边和一条边分配边消去。
(3)在一系列的简化后,如果能消去图中的所有边,使所有的进程结点都成为孤立结点,则称该图是可完全化简的;否则是不可完全化简的。
S为死锁的充分条件:当且仅当S状态的资源分配图是不可完全化简的。
死锁的解除:
如果利用死锁检测算法检测出在系统中已发生了死锁,应采取措施,解除死锁。
(1)抢占资源:
从其他进程抢占足够数量的资源给死锁进程。
(2)撤销进程:
终止所有进程或按照某种顺序逐个地撤销进程,直至有足够的资源可用,使死锁状态消除为止。
讨论:
并发性由高到低:
死锁检测并杀死进程
在死锁发生之前没有限制并发,因为依赖于运行时检查而不是静态限制。在检查到死锁后仍然允许大量并发。
银行家算法;资源排序
通过限制允许的计算范围而导致更多不必要的等待。
银行家的算法可用防止不安全的分配;资源排序限制了分配顺序。
提前预留所有资源
通过提前保留所有资源,线程必须等待更长时间,并且更有可能在工作时阻塞其他线程。
效率由高到低:
资源利用率由高到低:
习题:
为什么资源分配图具有循环,系统不一定处于死锁状态?
具有循环,但是如果资源充足的话,不会出现死锁。只有出现循环等待才可能出现死锁,即出现循环,并且所有进程都在等待分配资源。