死锁定义:

在一组进程发生死锁的情况下,这组死锁进程中的每个进程,都在等待另一个死锁进程所占有的资源。但是这些进程都无法运行,因此它们谁也不能不能释放资源,致使没有一个任何一个进程可被唤醒。这样一组只能无限期地等待下去。

思考:产生死锁的两个根本原因与操作系统的两个基本特征(并发和共享)之间存在着什么样的联系?

产生死锁的必要条件:

(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类型的资源。

if  Requesti[j]<=min(Need[i,j],Available[j]):
    Available[j]-=Requesti[j]
    Allocation[i,j]+=Requesti[j]
    Need[i,j]-=Requesti[j]
    执行安全性算法,检查此次资源分配后系统是否处于安全状态。
    如果安全,资源正式分配给进程Pi,否则恢复原来的状态
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

  安全性算法:

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的请求边和分配边,使之成为孤立的结点。

【操作系统】死锁概述_资源分配_02

(2)Pi释放资源后,便可使P2获得资源而继续运行,直至P2完成后又释放出它所占有的全部资源,

直至P2完成后又释放出它占有的资源,即P2的两条边请求边和一条边分配边消去。

【操作系统】死锁概述_资源分配_03

(3)在一系列的简化后,如果能消去图中的所有边,使所有的进程结点都成为孤立结点,则称该图是可完全化简的;否则是不可完全化简的。

S为死锁的充分条件:当且仅当S状态的资源分配图是不可完全化简的。

死锁的解除:

如果利用死锁检测算法检测出在系统中已发生了死锁,应采取措施,解除死锁。

(1)抢占资源:

从其他进程抢占足够数量的资源给死锁进程。

(2)撤销进程:

终止所有进程或按照某种顺序逐个地撤销进程,直至有足够的资源可用,使死锁状态消除为止。

讨论:

【操作系统】死锁概述_结点_04

 并发性由高到低:

死锁检测并杀死进程

在死锁发生之前没有限制并发,因为依赖于运行时检查而不是静态限制。在检查到死锁后仍然允许大量并发。

银行家算法;资源排序

通过限制允许的计算范围而导致更多不必要的等待。

银行家的算法可用防止不安全的分配;资源排序限制了分配顺序。

提前预留所有资源

通过提前保留所有资源,线程必须等待更长时间,并且更有可能在工作时阻塞其他线程。

效率由高到低:

资源利用率由高到低:

习题:

【操作系统】死锁概述_资源分配_05

 

【操作系统】死锁概述_死锁_06

为什么资源分配图具有循环,系统不一定处于死锁状态?

具有循环,但是如果资源充足的话,不会出现死锁。只有出现循环等待才可能出现死锁,即出现循环,并且所有进程都在等待分配资源。

【操作系统】死锁概述_资源分配_07