死锁的必要条件和解决方法

  1. 什么是死锁

     在多道程序设计环境中,若干进程往往要共享这类资源,而且一个进程所需要的资源不止一个。这样,就会出现若干进程竞争有限资源,又推进顺序不当,从而构成无限期循环等待的局面。这种状态就是死锁。系统发生死锁现象不仅浪费大量的系统资源,甚至导致整个系统崩溃,带来灾难性后果。所以,对于死锁问题在理论上和技术上都必须给予高度重视。 

     死锁是进程死锁的简称,是由Dijkstra于1965年研究银行家算法时首先提出来的。它是计算机操作系统乃至并发程序设计中最难处理的问题之一。实际上,死锁问题不仅在计算机系统中存在,在我们日常生活中它也广泛存在。

      所谓死锁,是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面。很显然,如果没有外力的作用,那麽死锁涉及到的各个进程都将永远处于封锁状态。从上面的例子可以看出,计算机系统产生死锁的根本原因就是资源有限且操作不当。即:一种原因是系统提供的资源太少了,远不能满足并发进程对资源的需求。这种竞争资源引起的死锁是我们要讨论的核心。例如:消息是一种临时性资源。某一时刻,进程A等待进程B发来的消息,进程B等待进程C发来的消息,而进程C又等待进程A发来的消息。消息未到,A,B,C三个进程均无法向前推进,也会发生进程通信上的死锁。另一种原因是由于进程推进顺序不合适引发的死锁。资源少也未必一定产生死锁。就如同两个人过独木桥,如果两个人都要先过,在独木桥上僵持不肯后退,必然会应竞争资源产生死锁;但是,如果两个人上桥前先看一看有无对方的人在桥上,当无对方的人在桥上时自己才上桥,那麽问题就解决了。所以,如果程序设计得不合理,造成进程推进的顺序不当,也会出现死锁。

2.产生死锁的必要条件

从以上分析可见,如果在计算机系统中同时具备下面四个必要条件时,那麽会发生死锁。换句话说,只要下面四个条件有一个不具备,系统就不会出现死锁。

   〈1〉互斥条件。即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有。这种独占资源如CD-ROM驱动器,打印机等等,必须在占有该资源的进程主动释放它之后,其它进程才能占有该资源。这是由资源本身的属性所决定的。如独木桥就是一种独占资源,两方的人不能同时过桥。

    〈2〉不可抢占条件。进程所获得的资源在未使用完毕之前,资源申请者不能强行地从资源占有者手中夺取资源,而只能由该资源的占有者进程自行释放。如过独木桥的人不能强迫对方后退,也不能非法地将对方推下桥,必须是桥上的人自己过桥后空出桥面(即主动释放占有资源),对方的人才能过桥。

    〈3〉占有且申请条件。进程至少已经占有一个资源,但又申请新的资源;由于该资源已被另外进程占有,此时该进程阻塞;但是,它在等待新资源之时,仍继续占用已占有的资源。还以过独木桥为例,甲乙两人在桥上相遇。甲走过一段桥面(即占有了一些资源),还需要走其余的桥面(申请新的资源),但那部分桥面被乙占有(乙走过一段桥面)。甲过不去,前进不能,又不后退;乙也处于同样的状况。

    〈4〉循环等待条件。存在一个进程等待序列{P1,P2,...,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一源,......,而Pn等待P1所占有的的某一资源,形成一个进程循环等待环。就像前面的过独木桥问题,甲等待乙占有的桥面,而乙又等待甲占有的桥面,从而彼此循环等待。

上面我们提到的这四个条件在死锁时会同时发生。也就是说,只要有一个必要条件不满足,则死锁就可以排除。

3. 解决死锁的方法

       前面介绍了死锁发生时的四个必要条件,只要破坏这四个必要条件中的任意一个条件,死锁就不会发生。这就为我们解决死锁问题提供了可能。一般地,解决死锁的方法分为死锁的预防,避免,检测与恢复三种(注意:死锁的检测与恢复是一个方法)。我们将在下面分别加以介绍。

1.死锁的预防  

      死锁的预防是保证系统不进入死锁状态的一种策略。它的基本思想是要求进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态

  〈1〉打破互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。

   〈2〉打破不可抢占条件。即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。    

    〈3〉打破占有且申请条件。可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。但是,这种策略也有如下缺点:

(1)在许多情况下,一个进程在执行之前不可能知道它所需要的全部资源。这是由于进程在执行时是动态的,不可预测的;

(2)资源利用率低。无论所分资源何时用到,一个进程只有在占有所需的全部资源后才能执行。即使有些资源最后才被该进程用到一次,但该进程在生存期间却一直占有它们,造成长期占着不用的状况。这显然是一种极大的资源浪费;

(3)降低了进程的并发性。因为资源有限,又加上存在浪费,能分配到所需全部资源的进程个数就必然少了。   

      <4>打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。这种策略与前面的策略相比,资源的利用率和系统吞吐量都有很大提高,但是也存在以下缺点:

(1)限制了进程对资源的请求,同时给系统中所有资源合理编号也是件困难事,并增加了系统开销;

(2)为了遵循按编号申请的次序,暂不使用的资源也需要提前申请,从而增加了进程对资源的占用时间。

2死锁的避免  

       上面我们讲到的死锁预防是排除死锁的静态策略,它使产生死锁的四个必要条件不能同时具备,从而对进程申请资源的活动加以限制,以保证死锁不会发生。下面我们介绍排除死锁的动态策略--死锁的避免,它允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,令进程等待。

  1. 安全序列

      我们首先引入安全序列的定义:所谓系统是安全的,是指系统中的所有进程能够按照某一种次序分配资源,并且依次地运行完毕,这种进程序列{P1,P2,...,Pn}就是安全序列。如果存在这样一个安全序列,则系统是安全的;如果系统不存在这样一个安全序列,则系统是不安全的。

     安全序列{P1,P2,...,Pn}是这样组成的:若对于每一个进程Pi,它需要的附加资源可以被系统中当前可用资源加上所有进程Pj当前占有资源之和所满足,则{P1,P2,...,Pn}为一个安全序列,这时系统处于安全状态,不会进入死锁状态。  

      当一个进程申请一个可用资源时, 系统必须决定: 是把该资源立即分给它, 还是让该进程等待, 仅当系统处于安全状态情况下才满足其申请。 

     虽然存在安全序列时一定不会有死锁发生,但是系统进入不安全状态(四个死锁的必要条件同时发生)也未必会产生死锁。当然,产生死锁后,系统一定处于不安全状态。 

      2.银行家算法

       众所周知, 避免死锁的著名算法叫做“银行家算法(Banker’s Algorithm)”。 其设计思想是当用户申请一组资源时, 系统必须确定: 如果把这些资源分出去, 系统是否还处于安全状态。 若是, 就可以分出这些资源; 否则, 该申请暂不予满足。

实现银行家算法要有若干数据结构, 用它们来表示资源分配系统的状态。 令n表示系统中进程的数目, m表示资源分类数。 还需要下列数据结构:

 (1) Available是一个长度为m的向量, 它表示每类资源可用的数量。  

 (2) Max是一个n×m矩阵, 它表示每个进程对资源的最大需求。

(3) Allocation是一个n×m矩阵, 它表示当前分给每个进程的资源数目。  

(4) Need是一个n×m矩阵, 它表示每个进程还缺少多少资源。  

  1. 资源分配算法

  令Requesti表示进程pi的申请向量。 若 Requesti[j]=k, 表示进程pi需要申请k个rj类资源。 当进程pi申请资源时, 就执行下列动作:

(1) 若Requesti>Needi, 表示出错, 进程对资源的申请量大于它说明的最大值。

 (2) 如果Requesti>Available, 则pi等待。

(3) 系统假设把申请的资源分给进程pi, 则相应数据结构被修改成如下状态:

           Available: =Available-Requesti;

           Allocationi: =Allocationi+Requesti;

           Needi: =Needi-Requesti。

   (4) 系统执行安全性算法, 查看此时系统是否处于安全状态。

 2. 安全性算法

为了找出一个系统是在安全状态还是在不安全状态下, 可采用下述算法:

   (1) 令Work和Finish分别表示长度为m和n的向量, 最初置Work =Available, Finish[i]=false, i=1, 2, …, n。

   (2) 找满足下列条件的i:

     ① Finish[i]=false;

     ② Needi≤Work。

    若没有找到, 则转向(4)。

 (3) Work:=Work+Allocationi(pi释放了所占的全部资源)

               Finish[i]=true转向(2)。

 (4) 若Finish[i]=true对所有i都成立(考虑到任一进程都可能是pi), 则系统处于安全状态; 否则, 系统处于不安全状态。

 虽然银行家算法相当通用, 并且适用于任何资源分配系统。其缺点是:

   〈1〉这个算法要求客户数保持固定不变,这在多道程序系统中是难以做到的。   

   〈2〉这个算法保证所有客户在有限的时间内得到满足,但实时客户要求快速响应,所以要考虑这个因素。  

    〈3〉由于要寻找一个安全序列,实际上增加了系统的开销。

3.死锁的检测与恢复  

       一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。

  1. 死锁检测算法:

 检测算法采用若干随时间变化的数据结构, 与银行家算法中所用的结构很相似。

  1. Available是一个长度为m的向量, 它说明资源的可用数目。

   (2) Allocation是一个n×m的矩阵, 它定义了当前分给每个进程的资源的数目。

    (3) Request是一个n×m的矩阵, 它表示当前每个进程对资源的申请情况。

  检测算法是简单地调查一下尚待完成的诸进程所有可能的分配序列。

     (1) 令Work和Finish分别表示长度为m和n的向量, 初始化Work: =Available。 如果Allocationi≠0, 则Finish[i]:=false, i=1, 2, …, n; 否则, Finish[i]:=true。

    (2) 找一个下标i, 它满足条件:

             ① Finish[i]=false;

             ② Requesti≤Work

   若找不到这样的i, 则转到(4)。

(3)Work:=Work+Allocationi

            Finish[i]=true

            转向(2)。

(4) 若对某些i(1≤i≤n), Finish[i]=false, 则系统处于死锁状态。 此外, 若Finish[i]=false, 则进程pi是死锁的。

        与前面结论相同, 当且仅当等待图含有环路时, 在系统中存在死锁。 为了检测死锁, 系统需要建立并修改等待图, 定期调用一个搜索图中环路的算法。这种检测环路的算法也需要进行很多操作。 当它的开销低于通常检测死锁算法时, 可以被采用。

与此相关, 何时调用检测算法的问题, 取决于以下两点:

         (1) 死锁出现的频繁程度;

         (2) 有多少个进程受到死锁影响。

2.从死锁中恢复

 1. 通过抢占资源实现恢复

    为了消除死锁可以采用抢占资源的方式, 即临时性地把资源从当前占有它的进程那儿拿过来, 分给另外某些进程, 直至死锁环路被打破。

     2.  通过回退执行实现恢复

     回退方法是由系统管理员做出安排的——定期对系统中各个进程进行检查, 并将检查点的有关信息(如进程状态、 资源状态等)写入文件, 以备今后重启时使用。  

    系统中应保存一系列检查点的文件, 即前后各检查点对应的文件不应覆盖。

   3.通过杀掉进程实现恢复

     通过强行终止进程可以解除死锁, 即系统从被终止的进程那里回收它们占有的全部资源, 然后分给其他等待这些资源的进程。 主要有两种方法:

         (1) 终止所有的死锁进程。

         (2) 一次终止一个进程, 直至消除死锁环路。

处理死锁的综合方式

       上面我们介绍了处理死锁的三种基本方法, 就是死锁的预防、 死锁的避免、 死锁的检测和恢复。 这三种方法有不同的资源分配策略和不同的方式, 各有其优点和缺点。对死锁的处理现在仍有争议, 还没有一种基本方式可对操作系统遇到的各式各样的资源分配问题能作出合适的处理。

 

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值