目录
1、死锁概述
(1)计算机中的资源分类
1.1 - 可重用性资源和消耗性资源
1.2 - 可抢占性资源和不可抢占性资源
(2)计算机系统中的死锁
(3)死锁的定义、必要条件和处理方法
3.1 - 死锁的定义
3.2 - 产生死锁的必要条件
3.3 - 处理死锁的方法
2、如何预防死锁?
(1)破坏“请求和保持”条件
1.1 - 一次性获取所需的全部资源
1.2 - 只获取部分资源即运行
(2)破坏“不可抢占”条件
(3)破坏“循环等待”条件
3、如何避免死锁?
(1)系统安全状态
1.1 - 安全状态
1.2 - 安全状态之例
(2)利用银行家算法避免死锁
4、死锁的检测与解除
(1)死锁的检测
(2)死锁的解除
1、死锁概述
(1)计算机中的资源分类
在系统中有许多不同类型的资源,其中可以引起死锁的主要是,采用互斥访问、不可以被抢占的资源,即临界资源。系统中这类资源有很多,如打印机、数据文件、队列、信号量等。
1.1 - 可重用性资源和消耗性资源
- 可重用性资源是一种可供用户重复使用多次的资源。每一个可重用性资源中的单元只能分配给一个进程使用,不允许多个进程共享。进程在使用可重用性资源时,必须遵循先请求资源,然后使用资源,最后释放资源的顺序。系统中每一类可重用性资源中的单元数目是相对固定的,进程在运行期间既不能创建也不能删除它。
- 可消耗性资源又称为临时性资源,它是在进程运行期间,由进程动态地创建和消耗的。最典型的可消耗性资源就是用于进程间通信的消息等。
1.2 - 可抢占性资源和不可抢占性资源
- 可抢占性资源,是指某进程在获得这类资源后,该资源可以再被其它进程或系统抢占。CPU 和主存均属于可抢占性资源,对于这类资源是不会引起死锁的。
- 不可抢占性资源,即一旦系统把某资源分配给该进程后,就不能将它强行收回,只能在进程用完后自行释放。例如,当一个进程已开始刻录光盘时,如果突然将刻录机分配给另一个进程,其结果必然会损坏正在刻录的光盘,因此只能等刻好光盘后由进程自己释放刻录机。另外磁带机、打印机等也都属于不可抢占性资源。
(2)计算机系统中的死锁
死锁的起因,通常是源于多个进程对资源的争夺,不仅对不可抢占资源进行争夺时会引起死锁,而且对可消耗资源进行争夺时,也会引起死锁。
上图中,m1,m2 和 m3 是可消耗资源。进程 P1 一方面产生消息 m1,利用 send(p2,m1) 原语将它发送给 P2;另一方面,它又要求从 P3 接收消息 m3,而进程 P2 一方面产生消息 m2,利用 send(p3,m3) 原语将它发送给 P3,另一方面它又需要接收进程 P1 所产生的消息 m1。类似地,进程 P3 也产生消息 m3,利用 send(p1,m3) 原语将它发送给 P1,而它又要求从进程 P2 接收其所产生的消息 m2。如果三个进程间的消息通信,按下述顺序进行:// 三个资源的闭环
P1: ...send(p2,m1); receive(p3,m3); ...
P2: ...send(p3,m2); receive(p1,m1); ...
P3: ...send(p1,m3); receive(p2,m2); ...
如果这三个进程都可以先将消息发送给下一个进程,相应地它们也都能够接收到从上一个进程发来的消息,因此三个进程可以顺利地运行下去,而不会发生死锁。但若改成三个进程都先执行 receive 操作,后执行 send 操作,即按下述的运行顺序:
P1: ...receive(p3,m3); ...send(p2,m1);
P2: ...receive(p1,m1); ...send(p3,m2);
P3: ...receive(p2,m2); ...send(p1,m3);
则这三个进程就会永远阻塞在它们的 receive 操作上,等待一条永远不会发出的消息,于是发生了死锁。// 这个例子有点绕,但是很好的阐释了可消耗资源引起的死锁问题
(3)死锁的定义、必要条件和处理方法
3.1 - 死锁的定义
在一组进程发生死锁的情况下,这组死锁进程中的每一个进程,都在等待另一个死锁进程所占有的资源。由于所有这些进程已都无法运行,因此它们谁也不能释放资源,致使没有任何一个进程可被唤醒。这样这组进程只能无限期地等待下去。
所以,如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程是死锁的(DeadLock)。//比较拗口,简单的来说就是都在无限期的等待资源
3.2 - 产生死锁的必要条件
虽然进程在运行过程中可能会发生死锁,但产生进程死锁是必须具备一定条件的。产生死锁必须同时具备下面四个必要条件,只要其中任一个条件不成立,死锁就不会发生:
- 互斥条件。进程对所分配到的资源进行排它性使用,即在一段时间内,某资源只能被一个进程占用。如果此时还有其它进程请求该资源,则请求进程只能等待,直至占有该资源的进程释放。
- 请求和保持条件。进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
- 不可抢占条件。进程已获得的资源在未使用完之前不能被抢占,只能在进程使用完时由自己释放。
- 循环等待条件。在发生死锁时,必然存在一个进程和资源的循环链。
3.3 - 处理死锁的方法
目前处理死锁的方法可归结为四种:
- 预防死锁。这是一种较简单和直观的事先预防方法。该方法是通过设置某些限制条件,去破坏产生死锁四个必要条件中的一个或几个来预防产生死锁。预防死锁是一种较易实现的方法,已被广泛使用。
- 避免死锁。同样是属于事先预防策略,但它并不是事先采取各种限制措施,去破坏产生死锁的四个必要条件,而是在资源的动态分配过程中,用某种方法防止系统进入不安全状态,从而可以避免发生死锁。
- 检测死锁。这种方法无须事先采取任何限制性措施,允许进程在运行过程中发生死锁。但可通过检测机构及时地检测出死锁的发生,然后采取适当的措施,把进程从死锁中解脱出来。
- 解除死锁。当检测到系统中已发生死锁时,就采取相应措施,将进程从死锁状态中解脱出来。常用的方法是撤消一些进程,回收它们的资源,将它们分配给已处于阻塞状态的进程,使其能继续运行。
上述的四种方法,从上到下对死锁的防范程度逐渐减弱,但对应的是资源利用率的提高,以及进程因资源因素而阻塞的频度下降(即并发程度提高)。//两全不能其美
2、如何预防死锁?
预防死锁的方法是通过破坏产生死锁的四个必要条件中的一个或几个,以避免发生死锁。由于互斥条件是非共享设备所必须的,不仅不能改变,还应加以保证,因此主要是破坏产生死锁的后三个条件。
(1)破坏“请求和保持”条件
为了能破坏“请求和保持”条件,系统必须保证做到:当一个进程在请求资源时,它不能持有不可抢占资源。该保证可通过如下两个不同的方式实现:
1.1 - 一次性获取所需的全部资源
使用该方式,所有进程在开始运行之前,必须一次性地申请其在整个运行过程中所需的全部资源。此时若系统有足够的资源分配给某进程,便可把其需要的所有资源分配给它。这样,该进程在整个运行期间,便不会再提出资源要求,从而破坏了“请求”条件。系统在分配资源时,只要有一种资源不能满足进程的要求,即使其它所需的各资源都空闲也不分配给该进程,而让该进程等待。由于该进程在等待期间未占有任何资源,于是破坏了“保持”条件,从而可以预防死锁的发生。
该方式的优点是简单、易行且安全。但缺点也极其明显:
- 资源被严重浪费,严重地恶化了资源的利用率。进程在开始运行时就一次性地占用了整个运行过程所需的全部资源,其中有些资源可能仅在运行初期或运行快结束时才使用,甚至根本不使用。
- 使进程经常会发生饥饿现象。因为仅当进程在获得了其所需的全部资源后才能开始运行,这样就可能由于个别资源长期被其它进程占用,而致使等待该资源的进程迟迟不能开始运行,而个别资源有可能仅在进程运行到最后才需要,如打印机往往就是如此。
1.2 - 只获取部分资源即运行
该方式是对第一种方式的改进,它允许一个进程只获得运行初期所需的资源后,便开始运行。进程运行过程中再逐步释放已分配给自己的、且已用毕的全部资源,然后再请求新的所需资源。
我们可以通过一个具体例子来说明,第二种方式比第一种方式要好。
例如,有一个进程,它所要完成的任务是,先将数据从磁带上复制到磁盘文件上,然后对磁盘文件进行排序,最后把结果打印出来。在采用第一种方式时,进程必须在开始时就请求磁带机、磁盘文件和打印机。然而打印机仅在最后才会用到,既影响到其利用率,还会影响到其它进程的运行。此外,又如磁带机和磁盘文件虽然空闲,但因打印机已分配给其它进程因而进程还需要等待。// 第一种方式:必须拥有:磁带机+磁盘文件+打印机
在采用第二种方式时,进程在开始时只需请求磁带机、磁盘文件,然后就可运行。等到全部磁带上的数据已复制到磁盘文件中并已排序好后,便可将磁带机和磁盘文件释放掉再去请求磁盘文件和打印机。这不仅能使进程更快地完成任务,提高设备的利用率,还可减少进程发生饥饿的机率。// 第二种方式:先拥有:磁带机+磁盘文件,然后再申请打印机
(2)破坏“不可抢占”条件
破坏“不可抢占”条件,即当一个已经保持了某些不可被抢占资源的进程,提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请。这意味着进程已占有的资源会被暂时地释放,或者说是被抢占了,从而破坏了“不可抢占”条件。//不能一直持有资源
该方式实现起来比较复杂,且需付出很大的代价。因为一个不可抢占的资源如打印机、CD 刻录机等在使用一段时间后被抢占,可能会造成进程前一阶段工作的失效,即使是采取了某些防范措施,也还会使进程前后两次运行的信息不连续。这种策略还可能因为反复地申请和释放资源致使进程的执行被无限地推迟,这不仅延长了进程的周转时间,而且也增加了系统开销,降低了系统吞吐量。//破坏不可抢占条件,代价比较大
(3)破坏“循环等待”条件
为了能保证“循环等待”条件不成立,需要对系统所有资源类型进行线性排序并赋予不同的序号。在对系统所有资源类型进行线性排序后,规定每个进程必须按序号递增的顺序请求资源。如果需要多个同类资源单元,则必须一起请求。//破环进程和资源的环路
在采用这种策略时,请求资源的顺序是十分重要的。一般情况下,进程总是先输入程序和数据,继而进行运算,最后将计算结果输出。故可以要求先获取输入设备(磁带机),然后再获取输出设备(打印机)。
这种预防死锁的策略与前两种策略比较,其资源利用率和系统吞吐量都有较明显的改善。但也存在下述问题:
- 首先,为系统中各类资源所规定的序号必须相对稳定,这就限制了新类型设备的增加。
- 其次,如果作业使用各类资源的顺序与系统规定的顺序不同,会造成对资源的浪费。
- 第三,为方便用户,系统对用户在编程时所施加的限制条件应尽量少,然而这种按规定次序申请资源的方法必然会限制用户简单、自主地编程。
3、如何避免死锁?
避免死锁同样是属于事先预防的策略,但并不是事先采取某种限制措施,破坏产生死锁的必要条件,而是在资源动态分配过程中,防止系统进入不安全状态,以避免发生死锁。这种方法所施加的限制条件较弱,可能获得较好的系统性能,目前常用此方法来避免发生死锁。
(1)系统安全状态
在死锁避免方法中,把系统的状态分为安全状态和不安全状态。当系统处于安全状态时,可避免发生死锁。反之,当系统处于不安全状态时,则可能进入到死锁状态。
1.1 - 安全状态
在该方法中,允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次资源分配的安全性。若此次分配不会导致系统进入不安全状态,才可将资源分配给进程,否则,令进程等待。
所谓安全状态,是指系统能按某种进程推进顺序(P1,P2,...,Pn)为每个进程 Pi 分配其所需资源,直至满足每个进程对资源的最大需求,使每个进程都可顺利地完成。此时称(P1,P2,...,Pn)为安全序列。如果系统无法找到这样一个安全序列,则称系统处于不安全状态。
虽然并非所有不安全状态都必然会转为死锁状态,但当系统进入不安全状态后,就有可能进入死锁状态。反之,只要系统处于安全状态,系统便不会进入死锁状态。因此,避免死锁的实质在于,系统在进行资源分配时,应使系统不进入不安全状态。// 能分配的资源是否足够,如果不足够,那么系统就是不安全的
1.2 - 安全状态之例
假定系统中有三个进程 P1、P2 和 P3,共有 12 台磁带机。进程 P1 总共要求 10 台磁带机,P2 和 P3 分别要求 4 台和 9 台。假设在 T0 时刻,进程 P1、P2 和 P3 已分别获得 5 台、2 台和 2 台磁带机,尚有 3 台空闲未分配,如下表所示:
经分析发现,在 T0 时刻系统是安全的,因为这时存在一个安全序列(P2,P1,P3),即只要系统按此进程序列分配资源,就能使每个进程都顺利完成。例如,将剩余的磁带机取 2 台分配给 P2,使之继续运行,待 P2 完成便可释放出 4 台磁带机,于是可用资源增至 5 台;以后再将这些全部分配给进程 P1,使之运行,待 P1 完成后,将释放出 10 台磁带机,P3 便能获得足够的资源,从而使 P1、P2、P3 每个进程都能顺利完成。// 所谓安全序列,就是使每一进程都能获得足够资源的运行顺序
(2)利用银行家算法避免死锁
银行家算法的思想:每当一个新进程在进入系统时,它必须申明在运行过程中,可能需要每种资源类型的最大单元数目,其数目不应超过系统所拥有的资源总量。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程。若有,再进一步计算在将这些资源分配给进程后,是否会使系统处于不安全状态。如果不会,才将资源分配给它,否则让进程等待。
// 总结:避免的死锁的核心思想,就是在资源动态分配过程中,防止系统进入不安全状态,也就是保障系统中有足够的资源。
// 必要时,手动实现下这个算法的逻辑
4、死锁的检测与解除
如果在系统中,既不采取死锁预防措施,也未配有死锁避免算法,系统很可能会发生
死锁。在这种情况下,系统应当提供两个算法:
- 死锁检测算法。该方法用于检测系统状态,以确定系统中是否发生了死锁。
- 死锁解除算法。当认定系统中已发生了死锁,利用该算法可将系统从死锁状态中解脱出来。
(1)死锁的检测
为了能对系统中是否已发生了死锁进行检测,在系统中必须
- 保存有关资源的请求和分配信息。
- 提供一种算法,它利用这些信息来检测系统是否已进入死锁状态。
//书中使用资源分配图作为例子,在此,不做过多描述,有兴趣看书
(2)死锁的解除
如果利用死锁检测算法检测出在系统中已发生了死锁,则应立即采取相应的措施,以解除死锁。
最简单的处理措施就是立即通知操作员,请操作员来以人工方法处理死锁。
另一种措施则是利用死锁解除算法,把系统从死锁状态中解脱出来。常采用解除死锁的两种方法是:// 自动解决死锁问题
- 抢占资源。从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以解除死锁状态。
- 终止(或撤消)进程。终止(或撤消)系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态解脱出来。
终止进程的方法有两种:终止所有死锁进程和逐个终止进程。终止所有死锁进程比较简单粗暴,全部终止即可。逐个终止进程方式,会考虑到进程终止的代价,终止进程时也会考虑进程的优先级,资源利用情况等,没有一个精确的度量标准,总之会比较复杂。//考虑终止代价最小化
// 在计算机中,所有求最优解的一个最大的问题是,计算机里边的东西是动态的,而我们往往使用静态的方式去思考问题,最终的结果就是,解决问题的方法很片面,或者说只能理论上可行。
// 比如,限定在一组数中去求解,对有限的数据进行分析,而实际情况却比这要复杂得多。事实是,我们不可能去全量论证一个问题的解,只能通过把动态的东西静态化,把复杂的东西简单化,一步一步去求解和探索规律。