操做系统 2009-09-24 16:48:58 阅读767 评论1 字号:大中小 订阅算法
1、要点提示安全
(1) 掌握死锁的概念和产生死锁的根本缘由。数据结构
(2) 理解产生死锁的必要条件--如下四个条件同时具有:互斥条件、不可抢占条件、占有且申请条件、循环等待条件。并发
(3) 记住解决死锁的通常方法,掌握死锁的预防和死锁的避免两者的基本思想。性能
(4) 掌握死锁的预防策略中资源有序分配策略。spa
(5) 理解进程安全序列的概念,理解死锁与安全序列的关系。操作系统
(6) 了解银行家算法。.net
(7) 了解资源分配图。设计
(8) 了解死锁的检测及恢复的思想。htm
2、内容简介
在计算机系统中有不少一次只能由一个进程使用的资源,如打印机,磁带机,一个文件的I节点等。在多道程序设计环境中,若干进程每每要共享这类资源,并且一个进程所须要的资源不止一个。这样,就会出现若干进程竞争有限资源,又推动顺序不当,从而构成无限期循环等待的局面。这种状态就是死锁。系统发生死锁现象不只浪费大量的系统资源,甚至致使整个系统崩溃,带来灾难性后果。因此,对于死锁问题在理论上和技术上都必须给予高度重视。
死锁是进程死锁的简称,是由Dijkstra于1965年研究银行家算法时首先提出来的。它是计算机操做系统乃至并发程序设计中最难处理的问题之一。实际上,死锁问题不只在计算机系统中存在,在咱们平常生活中它也普遍存在。
1.什么是死锁
咱们先看看这样一个生活中的例子:在一条河上有一座桥,桥面较窄,只能容纳一辆汽车经过,没法让两辆汽车并行。若是有两辆汽车A和B分别由桥的两端驶上该桥,则对于A车来讲,它走过桥面左面的一段路(即占有了桥的一部分资源),要想过桥还须等待B车让出右边的桥面,此时A车不能前进;对于B车来讲,它走过桥面右边的一段路(即占有了桥的一部分资源),要想过桥还须等待A车让出左边的桥面,此时B车也不能前进。两边的车都不倒车,结果形成互相等待对方让出桥面,可是谁也不让路,就会无休止地等下去。这种现象就是死锁。若是把汽车比作进程,桥面做为资源,那麽上述问题就描述为:进程A占有资源R1,等待进程B占有的资源Rr;进程B占有资源Rr,等待进程A占有的资源R1。并且资源R1和Rr只容许一个进程占用,即:不容许两个进程同时占用。结果,两个进程都不能继续执行,若不采起其它措施,这种循环等待情况会无限期持续下去,就发生了进程死锁。
在计算机系统中,涉及软件,硬件资源均可能发生死锁。例如:系统中只有一台CD-ROM驱动器和一台打印机,某一个进程占有了CD-ROM驱动器,又申请打印机;另外一进程占有了打印机,还申请CD-ROM。结果,两个进程都被阻塞,永远也不能自行解除。
所谓死锁,是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面。很显然,若是没有外力的做用,那麽死锁涉及到的各个进程都将永远处于封锁状态。从上面的例子能够看出,计算机系统产生死锁的根本缘由就是资源有限且操做不当。即:一种缘由是系统提供的资源太少了,远不能知足并发进程对资源的需求。这种竞争资源引发的死锁是咱们要讨论的核心。例如:消息是一种临时性资源。某一时刻,进程A等待进程B发来的消息,进程B等待进程C发来的消息,而进程C又等待进程A发来的消息。消息未到,A,B,C三个进程均没法向前推动,也会发生进程通讯上的死锁。另外一种缘由是因为进程推动顺序不合适引起的死锁。资源少也未必必定产生死锁。就如同两我的过独木桥,若是两我的都要先过,在独木桥上僵持不愿后退,必然会应竞争资源产生死锁;可是,若是两我的上桥前先看一看有无对方的人在桥上,当无对方的人在桥上时本身才上桥,那麽问题就解决了。因此,若是程序设计得不合理,形成进程推动的顺序不当,也会出现死锁。
从以上分析可见,若是在计算机系统中同时具有下面四个必要条件时,那麽会发生死锁。换句话说,只要下面四个条件有一个不具有,系统就不会出现死锁。
〈1〉互斥条件。即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有。这种独占资源如CD-ROM驱动器,打印机等等,必须在占有该资源的进程主动释放它以后,其它进程才能占有该资源。这是由资源自己的属性所决定的。如独木桥就是一种独占资源,两方的人不能同时过桥。
〈2〉不可抢占条件。进程所得到的资源在未使用完毕以前,资源申请者不能强行地从资源占有者手中夺取资源,而只能由该资源的占有者进程自行释放。如过独木桥的人不能强迫对方后退,也不能非法地将对方推下桥,必须是桥上的人本身过桥后空出桥面(即主动释放占有资源),对方的人才能过桥。
〈3〉占有且申请条件。进程至少已经占有一个资源,但又申请新的资源;因为该资源已被另外进程占有,此时该进程阻塞;可是,它在等待新资源之时,仍继续占用已占有的资源。还以过独木桥为例,甲乙两人在桥上相遇。甲走过一段桥面(即占有了一些资源),还须要走其他的桥面(申请新的资源),但那部分桥面被乙占有(乙走过一段桥面)。甲过不去,前进不能,又不后退;乙也处于一样的情况。
〈4〉循环等待条件。存在一个进程等待序列{P1,P2,...,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一源,......,而Pn等待P1所占有的的某一资源,造成一个进程循环等待环。就像前面的过独木桥问题,甲等待乙占有的桥面,而乙又等待甲占有的桥面,从而彼此循环等待。
上面咱们提到的这四个条件在死锁时会同时发生。也就是说,只要有一个必要条件不知足,则死锁就能够排除。
前面介绍了死锁发生时的四个必要条件,只要破坏这四个必要条件中的任意一个条件,死锁就不会发生。这就为咱们解决死锁问题提供了可能。通常地,解决死锁的方法分为死锁的预防,避免,检测与恢复三种(注意:死锁的检测与恢复是一个方法)。咱们将在下面分别加以介绍。
死锁的预防是保证系统不进入死锁状态的一种策略。它的基本思想是要求进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
〈1〉打破互斥条件。即容许进程同时访问某些资源。可是,有的资源是不容许被同时访问的,像打印机等等,这是由资源自己的属性所决定的。因此,这种办法并没有实用价值。
〈2〉打破不可抢占条件。即容许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能当即被知足时,它必须释放所占有的所有资源,之后再从新申请。它所释放的资源能够分配给其它进程。这就至关于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会下降系统性能。
〈3〉打破占有且申请条件。能够实行资源预先分配策略。即进程在运行前一次性地向系统申请它所须要的所有资源。若是某个进程所需的所有资源得不到知足,则不分配任何资源,此进程暂不运行。只有当系统可以知足当前进程的所有资源需求时,才一次性地将所申请的资源所有分配给该进程。因为运行的进程已占有了它所需的所有资源,因此不会发生占有资源又申请资源的现象,所以不会发生死锁。可是,这种策略也有以下缺点:
(1)在许多状况下,一个进程在执行以前不可能知道它所须要的所有资源。这是因为进程在执行时是动态的,不可预测的;
(2)资源利用率低。不管所分资源什么时候用到,一个进程只有在占有所需的所有资源后才能执行。即便有些资源最后才被该进程用到一次,但该进程在生存期间却一直占有它们,形成长期占着不用的情况。这显然是一种极大的资源浪费;
(3)下降了进程的并发性。由于资源有限,又加上存在浪费,能分配到所需所有资源的进程个数就必然少了。
(4)打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会造成环路。全部进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。这种策略与前面的策略相比,资源的利用率和系统吞吐量都有很大提升,可是也存在如下缺点:
(1)限制了进程对资源的请求,同时给系统中全部资源合理编号也是件困难事,并增长了系统开销;
(2)为了遵循按编号申请的次序,暂不使用的资源也须要提早申请,从而增长了进程对资源的占用时间。
8.3 死锁的避免
上面咱们讲到的死锁预防是排除死锁的静态策略,它使产生死锁的四个必要条件不能同时具有,从而对进程申请资源的活动加以限制,以保证死锁不会发生。下面咱们介绍排除死锁的动态策略--死锁的避免,它不限制进程有关申请资源的命令,而是对进程所发出的每个申请资源命令加以动态地检查,并根据检查结果决定是否进行资源分配。就是说,在资源分配过程当中若预测有发生死锁的可能性,则加以免。这种方法的关键是肯定资源分配的安全性。
1.安全序列
咱们首先引入安全序列的定义:所谓系统是安全的,是指系统中的全部进程可以按照某一种次序分配资源,而且依次地运行完毕,这种进程序列{P1,P2,...,Pn}就是安全序列。若是存在这样一个安全序列,则系统是安全的;若是系统不存在这样一个安全序列,则系统是不安全的。
安全序列{P1,P2,...,Pn}是这样组成的:若对于每个进程Pi,它须要的附加资源能够被系统中当前可用资源加上全部进程Pj当前占有资源之和所知足,则{P1,P2,...,Pn}为一个安全序列,这时系统处于安全状态,不会进入死锁状态。
虽然存在安全序列时必定不会有死锁发生,可是系统进入不安全状态(四个死锁的必要条件同时发生)也未必会产生死锁。固然,产生死锁后,系统必定处于不安全状态。
2.银行家算法
这是一个著名的避免死锁的算法,是由Dijstra首先提出来并加以解决的。
[背景知识]
一个银行家如何将必定数目的资金安全地借给若干个客户,使这些客户既能借到钱完成要干的事,同时银行家又能收回所有资金而不至于破产,这就是银行家问题。这个问题同操做系统中资源分配问题十分类似:银行家就像一个操做系统,客户就像运行的进程,银行家的资金就是系统的资源。
[问题的描述]
一个银行家拥有必定数量的资金,有若干个客户要贷款。每一个客户须在一开始就声明他所需贷款的总额。若该客户贷款总额不超过银行家的资金总数,银行家能够接收客户的要求。客户贷款是以每次一个资金单位(如1万RMB等)的方式进行的,客户在借满所需的所有单位款额以前可能会等待,但银行家须保证这种等待是有限的,可完成的。
例如:有三个客户C1,C2,C3,向银行家借款,该银行家的资金总额为10个资金单位,其中C1客户要借9各资金单位,C2客户要借3个资金单位,C3客户要借8个资金单位,总计20个资金单位。某一时刻的状态如图所示。
|
|
|
|
(a) |
(b) |
(c) |
(d) |
银行家算法示意
对于a图的状态,按照安全序列的要求,咱们选的第一个客户应知足该客户所需的贷款小于等于银行家当前所剩余的钱款,能够看出只有C2客户能被知足:C2客户需1个资金单位,小银行家手中的2个资金单位,因而银行家把1个资金单位借给C2客户,使之完成工做并归还所借的3个资金单位的钱,进入b图。同理,银行家把4个资金单位借给C3客户,使其完成工做,在c图中,只剩一个客户C1,它需7个资金单位,这时银行家有8个资金单位,因此C1也能顺利借到钱并完成工做。最后(见图d)银行家收回所有10个资金单位,保证不赔本。那麽客户序列{C1,C2,C3}就是个安全序列,按照这个序列贷款,银行家才是安全的。不然的话,若在图b状态时,银行家把手中的4个资金单位借给了C1,则出现不安全状态:这时C1,C3均不能完成工做,而银行家手中又没有钱了,系统陷入僵持局面,银行家也不能收回投资。
综上所述,银行家算法是从当前状态出发,逐个按安全序列检查各客户谁能完成其工做,而后假定其完成工做且归还所有贷款,再进而检查下一个能完成工做的客户,......。若是全部客户都能完成工做,则找到一个安全序列,银行家才是安全的。
从上面分析看出,银行家算法容许死锁必要条件中的互斥条件,占有且申请条件,不可抢占条件的存在,这样,它与预防死锁的几种方法相比较,限制条件少了,资源利用程度提升了。
这是该算法的优势。其缺点是:
〈1〉这个算法要求客户数保持固定不变,这在多道程序系统中是难以作到的。
〈2〉这个算法保证全部客户在有限的时间内获得知足,但实时客户要求快速响应,因此要考虑这个因素。
〈3〉因为要寻找一个安全序列,实际上增长了系统的开销。
8.4 死锁的检测与恢复
通常来讲,因为操做系统有并发,共享以及随机性等特色,经过预防和避免的手段达到排除死锁的目的是很困难的。这须要较大的系统开销,并且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采起任何限制性措施,可是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。所以,在实际的操做系统中每每采用死锁的检测与恢复方法来排除死锁。 死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构可以检测到死锁发生的位置和缘由,并能经过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。 1.放大观看>>)
图中所示为一个小的死锁的例子。这时进程P1占有资源R1而申请资源R2,进程P2占有资源R2而申请资源R1,按循环等待条件,进程和资源造成了环路,因此系统是死锁状态。进程P1,P2是参与死锁的进程。 下面咱们再来看一看死锁检测算法。算法使用的数据结构是以下这些: 占有矩阵A:n*m阶,其中n表示并发进程的个数,m表示系统的各种资源的个数,这个矩阵记录了每个进程当前占有各个资源类中资源的个数。 申请矩阵R:n*m阶,其中n表示并发进程的个数,m表示系统的各种资源的个数,这个矩阵记录了每个进程当前要完成工做须要申请的各个资源类中资源的个数。 空闲向量T:记录当前m个资源类中空闲资源的个数。 完成向量F:布尔型向量值为真(true)或假(false),记录当前n个并发进程可否进行完。为真即能进行完,为假则不能进行完。 临时向量W:开始时W:=T。 算法步骤: (1)W:=T, 对于全部的i=1,2,...,n, 若是A[i]=0,则F[i]:=true;不然,F[i]:=false (2)找知足下面条件的下标i: F[i]:=false而且R[i]〈=W 若是不存在知足上面的条件i,则转到步骤(4)。 (3)W:=W+A[i] F[i]:=true 转到步骤(2) (4)若是存在i,F[i]:=false,则系统处于死锁状态,且Pi进程参与了死锁。什麽时候进行死锁的检测取决于死锁发生的频率。若是死锁发生的频率高,那麽死锁检测的频率也要相应提升,这样一方面能够提升系统资源的利用率,一方面能够避免更多的进程卷入死锁。若是进程申请资源不能知足就马上进行检测,那麽每当死锁造成时即能被发现,这和死锁避免的算法相近,只是系统的开销较大。为了减少死锁检测带来的系统开销,通常采起每隔一段时间进行一次死锁检测,或者在CPU的利用率下降到某一数值时,进行死锁的检测。 2.死锁的恢复 一旦在死锁检测时发现了死锁,就要消除死锁,使系统从死锁状态中恢复过来。 (1)最简单,最经常使用的方法就是进行系统的从新启动,不过这种方法代价很大,它意味着在这以前全部的进程已经完成的计算工做都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程。 (2)撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。这时又分两种状况:一次性撤消参与死锁的所有进程,剥夺所有资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。通常来讲,选择逐步撤消的进程时要按照必定的原则进行,目的是撤消那些代价最小的进程,好比按进程的优先级肯定进程的代价;考虑进程运行时的代价和与此进程相关的外部做业的代价等因素。 此外,还有进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时再也不发生死锁。虽然这是个较理想的办法,可是操做起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便从此的回退,有时这是没法作到的。 |