死锁检测与恢复

注:本文主要参考自<<现代操作系统>>6.3,6.4节

死锁一文中,我们提到死锁问题有四种解决方案.本文将主要介绍第二种方法:死锁检测与恢复.

此处简要提及一下第一种方法,忽略死锁.如果程序员可以推断死锁发生的概率非常小,且发生死锁后不会造成严重后果.则可以考虑忽略死锁,毕竟解决死锁问题不仅需要编写额外代码,死锁解决方案本身也会对程序性能造成影响.例如我们即将介绍的死锁检测与恢复方法中.需要持续判断当前是否发生了死锁,这是一个不小的开销.

死锁检测与恢复

使用这种技术,我们并不试图区阻止死锁的发生,而是及时检测死锁是否发生.当检测到死锁发生时,尝试进行恢复以消除死锁.

每种类型只有一个资源

我们首先介绍每种类型只有一个资源的情形.例如, 当前仅有一台打印机可用.此时所有需要使用打印机的进程都要竞争这一台打印机.对于该问题,我们可以使用在死锁一节中提到的资源分配图解决.

在每一次资源请求后,我们都需要检测当前资源分配图中是否存在环路,如果存在环路,则表示当前环路上的进程发生了死锁. 因此可以使用有向图中回路检测算法来判断是否发生死锁.

每种类型有多个资源

在此类情形中,每种类型有多个资源,一个进程也可能需要获取一种类型的多个资源.特别注意,在后面分析中,我们假设进程一次性请求其所需的所有资源.
假设共有mm种资源,我们使用向量E=(E1,E2,...,Em)E=(E_1, E_2, ..., E_m)表示每种资源的数量.例如E1=4E_1=4表示第一种资源的总数为4.使用向量A=(A1,A2,...,Am)A=(A_1, A_2, ..., A_m)表示当前资源的可用数量.例如A1=2A_1=2表示当前第一种资源剩余两个可用.假设共有nn个进程,使用矩阵Cn×mC_{n\times m}表示进程已分配资源.其中C[1][2]C[1][2]表示进程1已经占有的第二种资源的个数.使用矩阵Rn×mR_{n\times m}表示当前进程的请求资源数, .例如, R[1][2]R[1][2]表示当前时刻进程1正请求的第二种资源的数量.

基于以上,我们可以使用一种标记算法来判断当前时刻进程中是否发生死锁, 如果发生死锁,涉及到哪些进程.在初始时,所用进程都未被标记.
使用如下算法对进程进行标记:

  1. 如果当前进程尚未被标记,且RiAR_i \le A, 则当前进程请求的资源可以被分配.如果找不到符合要求的进程,则算法终止.
  2. 分配资源, Ci+=RiC_i += R_i, A=RiA -= R_i.
  3. 进程执行完毕后,将释放其占用的资源,因此A+=CiA += C_i
  4. 转回步骤1.
    在算法执行完成后,如果有进程尚未被标记,则系统中存在死锁, 其中未标记的进程为死锁涉及的进程.

接下来通过一个简单的例子讲解标记算法.
在这里插入图片描述

当前共有三个进程, 此时进程1与进程2都无法被标记,因为AR1A \le R_1, AR2A \le R_2, 但进程3所需的资源可以被满足.因此进程3被标记.在进程3执行完成后,将释放它占用的资源, 此时A=(2,2,2,0)A = (2, 2, 2, 0), 再次执行标记步骤,此时进程1的资源请求与进程2的资源请求均能被满足,因此系统中不存在死锁.

何时执行死锁检测

现在我们知道了如何检测死锁(至少是在这种预先知道静态资源请求的情况下),但问题在于何时去检测它们。一种方法是每当有资源请求时去检测。毫无疑问越早发现越好,但这种方法会占用昂贵的CPU时间。另一种方法是每隔k分钟检测一次,或者当CPU的使用率降到某一域值时去检测。考虑到CPU使用效率的原因,如果死锁进程数达到一定数量,就没有多少进程可运行了,所以CPU会经常空闲。

从死锁中恢复

当我们检测到系统中存在死锁后,就需要考虑如何对系统进行恢复,以消除死锁.此处介绍3种可能的方法.

1.利用抢占恢复

在某些情况下,可能会临时将某个资源从它的当前所有者那里转移到另一个进程。许多情况下,尤其是对运行在大型主机上的批处理操作系统来说,需要人工进行干预。

比如,要将激光打印机从它的持有进程那里拿走,管理员可以收集已打印好的文档并将其堆积在一旁。然后,该进程被挂起(标记为不可运行)。接着,打印机被分配给另一个进程。当那个进程结束后,堆在一旁的文档再被重新放回原处,原进程可重新继续工作。

在不通知原进程的情况下,将某一资源从一个进程强行取走给另一个进程使用,接着又送回,这种做法是否可行主要取决于该资源本身的特性。用这种方法恢复通常比较困难或者说不太可能。若选择挂起某个进程,则在很大程度上取决于哪一个进程拥有比较容易收回的资源。

2.利用回滚恢复

如果系统设计人员以及主机操作员了解到死锁有可能发生,他们就可以周期性地对进程进行检查点检查(checkpointed)。进程检查点检查就是将进程的状态写入一个文件以备以后重启。该检查点中不仅包括存储映像,还包括了资源状态,即哪些资源分配给了该进程。为了使这一过程更有效,新的检查点不应覆盖原有的文件,而应写到新文件中。这样,当进程执行时,将会有一系列的检查点文件被累积起来。

假设,检测到进程1与进程2构成死锁.进程1需要的资源A此时被进程2占用.我们准备通过重新分配资源满足进程1,从而消除死锁.此时,我们需要检查进程2的检查点,将其恢复到某一检查点文件上, 在该检查点上,进程2尚未占用资源A. 通过对进程2进程复位,其在检查点后的所有工作将被清除.然后我们可以把资源A分配给进程1.如果复位后的进程2试图重新获得对该资源的控制,它必须等到该资源可用时为止, 至少需要在进程1执行完毕并释放该资源后.

3.通过杀死进程恢复

最直接也是最简单的解决死锁的方法是杀死一个或若干个进程。一种方法是杀掉环中的一个进程。如果走运的话,其他进程将可以继续。如果这样做行不通的话,就需要继续杀死别的进程直到打破死锁环。

另一种方法是选一个环外的进程作为牺牲品以释放该进程的资源。在使用这种方法时,选择一个要被杀死的进程要特别小心,它应该正好持有环中某些进程所需的资源。比如,一个进程可能持有一台绘图仪而需要一台打印机,而另一个进程可能持有一台打印机而需要一台绘图仪,因而这两个进程是死锁的。第三个进程可能持有另一台同样的打印机和另一台同样的绘图仪而且正在运行着。杀死第三个进程将释放这些资源,从而打破前两个进程的死锁。

有可能的话,最好杀死可以从头开始重新运行而且不会带来副作用的进程。比如,编译进程可以被重复运行,由于它只需要读入一个源文件和产生一个目标文件。如果将它中途杀死,它的第一次运行不会影响到第二次运行。

另一方面,更新数据库的进程在第二次运行时并非总是安全的。如果一个进程将数据库的某个记录加1,那么运行它一次,将它杀死后,再次执行,就会对该记录加2,这显然是错误的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章