死锁的概念

概述

由 Dijkstra 提出的哲学家进餐问题(The Dinning Philosophers Problem)是典型的进程同步问题。该问题描述的是有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,在饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子的时候才能够进餐。进餐完毕后,放下筷子继续思考。

在上述问题中,假设五个哲学家同时进入饥饿的状态,会同时拿起身边左边最靠近自己的筷子,但当有一个哲学家想要拿起右边最靠近自己的筷子时,由于该筷子已被拿起,并且获取该筷子的哲学家不放下,而造成无限地等待,这种特殊现象就被称之为死锁。


定义

每个进程所等待的事件是该组中其他进程释放所占有的资源,由于所有这些进程处于阻塞态,都无法正常运行,因此它们谁也不能释放资源,致使没有任何一个进程可被唤醒。这样这组进程只能无限期地等待下去。由此可以给死锁做出如下的定义:

如果一组进程中的每一个进程都在等待仅由该组进程中的其他进程才能引发的时间,那么该组进程是死锁(Deadlock)。


产生死锁的必要条件

虽然进程在运行过程中可能会发生死锁,但产生进程死锁是必须具备一定条件的。综上所述,产生死锁必须同时具备下面四个必要条件,只要其中任意一个条件不成立,死锁就不会发生。

  1. 互斥条件。进程对所分配到的资源进行排他性使用,即在一段时间内,某资源只能被一个进程占用。如果此时还有其它进程请求该资源,则请求进程只能等待,直至占有该资源的进程使用完后,进行释放。
  2. 请求和保持条件。进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
  3. 不可抢占条件。进程已获得的资源在未使用完之前不能被抢占,只能在进程使用完时自己释放。
  4. 循环等待条件。在发生死锁时,必然存在一个进程-资源的循环链,即进程集合 {A, B, C, D, ..} 中 A 正在等待一个 B 占用的资源,B 正在等待 C 占用的资源,… ,Z 正在等待已被 A 占用的资源。

处理死锁的方法

目前处理死锁的方法可归纳总结为四种:

  1. 预防死锁。这是一个较简答和直观的事先预防方法。该方法是通过设置某些限制条件,去破坏产生死锁四个条件的一个或几个来预防死锁。预防死锁是一种较易实现的方法,已被广泛使用。
  2. 避免死锁。同样是属于事先预防策略,但它并不是事先采取各种限制措施,去破坏产生死锁的四个必要条件,而是在资源的动态分配中,用某些方法防止系统进入不安全状态,从而避免发生死锁。
  3. 监测死锁。这种方法无须事先采取任何限制性措施,而是允许进程在运行过程中发生死锁。但该方法可以通过检测机制及时地检测出死锁的发生,根据检测结果,采取某些适当的措施。
  4. 解除死锁。当检测到系统中已发生死锁时,就采取相应措施,将进程从死锁状态中释放。常用的方法是撤销一些进程,强制回收它们的资源,将它们分配给已处于阻塞状态的进程,使其能够继续运行。

上述的四种方法,从(1)到(4)对死锁的防范程度逐渐减弱,但相对应的是对资源利用率的提高,以及进程因资源因素而阻塞的频率下降(即并发程度提高)。