操作系统9————死锁

操作系统9————死锁

一. 目录

二. 死锁的概述

在前几篇博客的哲学家问题中,当时我们提起过如果所有的哲学家同时拿起左边的筷子,就会因为无筷子可用,陷入无限等待的情况,这就是我们所说的死锁现象。接下来我们系统的说一下死锁的概念及处理。

1.死锁的定义

如果一组进程中的每一个进程都在等待仅有该组进程的其他进程才能引发的事件(等待其他进程所占有的资源),那么该组进程是死锁的。

2.产生死锁的必要条件

产生死锁必须同时具备下面四个必要条件,只有其中一个条件不成立,死锁就不会发生。

  • 互斥条件。进程对所分配的资源进行排他性使用。即该资源只允许一个进程使用,其他进程如果请求该资源只能等待。
  • 请求和保持条件。进程已经保持一至少一个资源,但又提出了新的资源请求,而新资源已被其他进程占有,导致进程被阻塞。
  • 不可抢占条件。 进程已获得的资源在为使用完之前不能被抢占,只有进程在使用完之后才能释放。
  • 循环等待条件。发生死锁时,必然存在一个进程资源循环链,即进程集合[ p 0 , p 1 , p 2 p n ]中 p 0 等待 p 1 的资源, p 1 等待 p 2 的资源…. p n 1 等待 p n 的资源

3.死锁的处理

死锁的处理可以分为下面这四种:

  • 预防死锁。该方法是通过产生死锁的四个必要条件中的一个或者几个来预防产生死锁。
  • 避免死锁。该方法是在资源的动态分配的过程中,用某种方法预防系统进入不安全状态,从而可以避免发生死锁
  • 检测死锁。该方法允许进程发生死锁,但可以检测死锁的发生,然后通过适当的措施将进程解脱出来。
  • 解除死锁。当已经检测出死锁时,就采用相应的措施,将进程解脱出来,常用的方法是撤销一些进程,回收他们的资源。将他们分配给处于阻塞状态的进程。

三. 预防死锁

1. 破坏“请求和保存”条件

为了破坏“请求和保持”条件,可以通过以下两个不同的协议实现:

a.第一种协议
该协议规定,所有进程在开始运行之前,必须一次性的申请其整个运行过的所需要的全部资源。此时若系统有足够的资源分配某进程,则破坏了“请求”条件。如果系统资源不足,则破坏了“保持条件”。

第一种协议简单,易行且安全,但缺点也比较明显

  • 资源被验证浪费,严重恶化了资源的利用率
  • 使进程经常发生饥饿现象。

b.第二种协议
该协议是对第一种协议的改进,它允许一个进程只获得运行初期所需的资源后,便开始运行。进程运行过程中再逐步释放已分配的,且已经用完的全部资源,再去请求新的资源。

第二种协议相比于第一种协议而言,提供的资源的利用率,也减少了进程发生饥饿的几率。

2. 破坏“不可抢占”条件

为了能破坏“不可抢占”条件,协议中规定,当一个已经保持了某些不可被抢占资源的进程,提出新的资源请求而不能得到满足,它必须释放已经保持的所有资源,待以后需要时再重新申请。 这意味着进程已占用的资源会暂时释放,从而破坏了“不可抢占的”条件。

3. 破坏”循环等待”条件

一个能保证“循环等待”条件不成立的方法是,对系统所有资源类型进行线性排序,并赋予不同的序号。排序后,便可以采用这样的预防协议:规定每个进程必须按照序号的地址顺序来请求资源。一个进程在开始时,可以请求资源 R i 的单元,以后,当且仅当 F ( R j ) > F ( R i ) ,进程才可以请求资源 R j .如果需要多个同类资源单元,则必须一起请求。

优点:资源利用率和系统吞吐量都有比较明显的改善。
缺点:

  • 系统中各类资源所规定的序号必须稳定,这就限制了新类型设备的增加
  • 可能会发生作业使用各类资源的顺序与系统规定的·爱护你在·不同·,造成资源的浪费。
  • 这种按照规定次序申请资源的方法会限制用户简单,自主的编程。

四. 避免死锁(银行家算法)

在避免死锁方法中,把系统的状态分为安全状态和不安全状态。安全状态中,可避免死锁状态.不安全状态中,进程可能进入死锁状态。避免死锁方法的基本思想就是,让系统始终处于安全状态。

最具有代表性避免死锁的算法就是Dijkstra的银行家算法。

基本思想:在每个新进程进入系统时,他必须声明在运行过程中,可能需要的每种资源类型的最大单元数目(数目不超过系统拥有的资源总量)。当系统请求一组资源时,系统必须首先在确定是否有足够的资源分配给该进程。若有,在进一步计算将这些资源分配给进程后,是否会使系统处于不安全状态。如果不会,才将资源分配给他。

1.银行家算法的数据结构

为实现银行家算法,在系统中必须要有这样四个数据结构,分别用来描述系统中可利用的资源,所有进程对资源的最大需求,系统中的资源分配,以及所有进程还需要资源的情况。

a.可利用资源Available:这是一个含有m个元素的数组,其中每一个元素代表一类可利用的资源情况。其初始值是系统所配置的全部可用资源的数目。 如果Available[j] = k,则表示系统中现有 R j 类资源k个。

b.最大需求矩阵Max: 这是一个n*m的矩阵。它定义了系统中n个进程每一个对m类资源的最大需求。如果Max[i,j] = K,则表示进程i需要 R j 类资源的最大数目为K。

c.分配矩阵Allocation:这也是一个n*m矩阵,它定义了系统中每一类资源当前已分配给每一类进程的资源。如果Allocation[i.j]= K ,则表示进程i已分得 R j 类资源的数目为K。

d.需求矩阵Need:这也是n*m的矩阵,用来表示每一个进程尚需的各类资源数,如果Need[i,j]=K,则表示进程i还需要K个 R j 类资源才能完成任务。

2.银行家算法

R e q u e s t i P i 进程的请求向量,如果 R e q u e s t i [ j ] = K 则表示 P i 进程需要K个 R j 类资源。
P i 发出资源请求后,系统按照下述步骤进行检查。

a. 如果 R e q u e s t i [ j ] n e e d [ i , j ] 便转向步骤b,否则认为错误,因为它所需要的资源数已超过它宣布的最大值。
b. R e q u e s t i [ j ] A v a i l a b l e [ i , j ] 便转向步骤b,否则认为错误,表示尚无足够资源, P i 等待。
c.系统试探把资源分配给进程 P i ,并修改下面数据结构的值

  • A v a i l a b l e p [ j ] = A v a i l a b l e [ j ] R e q u e s t i [ j ]
  • A l l o c a t i o n [ i , j ] = A l l o c a i o n [ i , j ] + R e q u e s t i [ j ]
  • N e e d [ i , j ] = N e e d [ i , j ] R e q u e s t i [ j ]

d.系统执行安全性算法,检查此次分配是否处于安全状态,若属于安全状态,则将资源正式分配给进程 P i 。已完成本次分配。否则将本次试探分配作废,恢复原来的资源分配状态,让进程 P i 等待。

3. 安全性算法

系统所描述的安全性算法可以描述为下:
数据结构

  • 工作向量Work,它表示可以提供给进程继续运行所需要的各类的资源数目,它含有m个元素,在执行安全算法开始时,Work = Available;
  • Finish,它表示系统是否有足够的资源分配给进程,使之运行完成。开始先做Finish[i] = false.当有足够资源分配给进程时,再灵FInish[i] = true;

算法思想
a. 从进程集合中找到一个满足下述条件的进程:Finish[i] = true;Need[i,j]<=Work.如果找到执行步骤b,否则执行步骤c;
b.当进程 P i 获得资源后,可顺利执行,直到完成,并释放它的资源。故应执行:

  • Work[j] = Work[j] - Allocation[i,j];
  • Finish[j] =true;
  • 返回执行步骤a

c.如果所有进程的Finish[i] = true都满足,则表示系统处于安全状态;否则,系统处于不安全状态。

4.银行家算法例子

假定系统中有五个进程{P0, P1, P2, P3, P4}和三类资源{A, B, C},各种资源的数量分别为10、5、7,在T0时刻的资源分配情况如下图所示。
这里写图片描述

(1) T0时刻的安全性:利用安全性算法对T0时刻的资源分配情况进行分析(如下图)可知,在T0时刻存在着一个安全序列{P1, P3, P4, P2, P0},故系统是安全的。
这里写图片描述

(2)  P1请求资源:P1发出请求向量Request1(1, 0, 2),系统按银行家算法进行检查:   
① Request1(1, 0, 2)≤Need1(1, 2, 2);   
② Request1(1, 0, 2)≤Available1(3, 3, 2);   
③ 系统先假定可为P1分配资源,并修改Available,Allocation1和Need1向量,由此形成的资源变化情况如第一幅图中的圆括号所示;   
④ 再利用安全性算法检查此时系统是否安全,如图下图所示。
这里写图片描述

五. 检测死锁

检测死锁算法用于检测系统状态,来确定系统中是否发生了死锁。

1.资源分配图

系统死锁,可利用资源分配图来描述。

该图是由一组结点N和一组边E所组成的一个对偶G = (N, E),它具有下述形式的定义和限制:   

  • 把N分为两个互斥的子集,即一组进程结点P={ P 1 , P 2 , , P n }和一组资源结点R={ R 1 , R 2 , , R n },N = P∪R。在下图所示的例子中,P = { P 1 , P 2 },R = { R 1 , R 2 },N = { P 1 , P 2 }∪{ R 1 , R 2 }}。   
  • 凡属于E中的一个边e∈E,都连接着P中的一个结点和R中的一个结点,e = {Pi, Rj}是资源请求边,由进程Pi指向资源Rj,它表示进程Pi请求一个单位的Rj资源。E = {Rj,Pi}是资源分配边,由资源Rj指向进程Pi,它表示把一个单位的资源Rj分配给进程Pi。下图中示出了两个请求边和两个分配边,即E = {(P1, R2), (R2, P2), (P2, R1), (R1, P1)}。
    这里写图片描述

2.死锁定理

我们可以利用把资源分配图加以简化的方法,来检测当系统处于S状态时,是否为死锁状态。简化方法如下:

  • 在资源分配图中,找出一个既不阻塞又非独立的进程结点Pi。在顺利的情况下, P i 可获得所需资源而继续运行,直至运行完毕,再释放其所占有的全部资源,这相当于消去Pi的请求边和分配边,使之成为孤立的结点。在图3-20(a)中,将P1的两个分配边和一个请求边消去,便形成图(b)所示的情况。
  • 重复上述过程,若能消去图中所有的边,则称该图是可以简化的,如果不能小区所有的边消去,则称该图是不可完全简化的。

S状态为死锁状态的充分条件:当且仅当S状态的资源分配图是可以完全简化的。
这里写图片描述

3.检测死锁算法

死锁检测中的数据结构类似于银行家算法中的数据结构:   

  • 可利用资源向量Available,它表示了m类资源中每一类资源的可用数目。   
  • 把不占用资源的进程(向量Allocation=0)记入L表中,即Li∪L。   
  • 从进程集合中找到一个Requesti≤Work的进程,做如下处理:①将其资源分配图简化,释放出资源,增加工作向量Work =Work + Allocation i。② 将它记入L表中。   
  • 若不能把所有进程都记入L表中,便表明系统状态S的资源分配图是不可完全简化的。因此,该系统状态将发生死锁。

六. 解除死锁

如果利用死锁检测算法检测已经发生死锁。则应该立即采取相应的措施,来解除死锁,即利用解除死锁算法来解除算法。常用来解除死锁的两种方法:

  • 抢占资源,从一个或多个进程抢占足够的资源,分配给死锁进程,来解除死锁状态。
  • 终止进程,终止系统中一个或者多个死锁进程,直至打破循环环路,是系统从死锁状态解脱出来。

七. 参考资料

《操作系统第四版》

猜你喜欢

转载自blog.csdn.net/qq_38499859/article/details/80896453
今日推荐