Skip to content

死锁的原因是什么,如何解决死锁

死锁是指在多道程序设计中,两个或两个以上的进程(或线程)因争夺资源而造成的一种互相等待的僵局,若无外力作用,它们都将无法继续推进。 例如,进程A占有资源1,并等待资源2,而进程B占有资源2,并等待资源1,此时两个进程都无法继续执行,就形成了一个死锁。

死锁产生的原因和必要条件

死锁的产生并非偶然,它必须同时满足以下四个必要条件,缺一不可:

  1. 互斥条件 (Mutual Exclusion):指一个资源在同一时刻只能被一个进程所使用。 如果其他进程请求该资源,则必须等待,直到资源被释放。这是许多资源(如打印机、处理器)固有的特性,通常无法破坏。

  2. 请求与保持条件 (Hold and Wait):指进程已经至少保持了一个资源,但又提出了新的资源请求,而该资源已被其他进程占用,此时请求进程被阻塞,但对自己已获得的资源保持不放。

  3. 不可剥夺条件 (No Preemption):指进程已获得的资源,在未使用完之前,不能被其他进程强行剥夺,只能由获得该资源的进程自己释放。

  4. 循环等待条件 (Circular Wait):在发生死锁时,必然存在一个进程—资源的环形链,即进程集合{P0, P1, …, Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

除了这四个必要条件,导致死锁的具体原因还包括: * 资源竞争:当系统中可供多个进程共享的资源不足时,进程会因争夺资源而陷入僵局。 * 进程推进顺序不当:进程在运行过程中,请求和释放资源的顺序不当,也可能导致死锁。

如何解决死锁

解决死锁的方法通常分为四大类:死锁预防死锁避免死锁检测与解除,以及忽略该问题(如鸵鸟算法)。

1. 死锁预防 (Deadlock Prevention)

死锁预防是通过破坏产生死锁的四个必要条件中的一个或多个来防止死锁的发生。

  • 破坏请求与保持条件
    • 一次性分配所有资源:要求每个进程在开始执行前,一次性地申请其在整个运行过程中所需的全部资源。 这样做的好处是简单,但缺点是资源浪费严重,且可能导致进程“饥饿”(即进程可能因为无法一次性获得所有资源而长时间无法运行)。
  • 破坏不可剥夺条件
    • 允许资源剥夺。 当一个已经保持了某些资源的进程,再请求新的资源而不能立即得到满足时,它必须释放所有已经保持的资源。另一种方式是,操作系统可以剥夺其他进程占有的资源。 这种策略实现起来比较复杂,且可能导致前一进程的工作前功尽弃。
  • 破坏循环等待条件
    • 资源有序分配法:将系统中的所有资源进行线性排序,并赋予不同的序号。所有进程对资源的请求必须严格按序号递增的顺序提出。 这样就破坏了循环等待的条件。这是目前应用最广泛的死锁预防策略。

2. 死锁避免 (Deadlock Avoidance)

死锁预防的策略通常会降低系统的并发性。死锁避免则是一种更动态的方法,它在资源分配过程中,通过算法来判断本次分配是否会导致系统进入不安全状态,从而避免死锁的发生。

  • 安全状态:系统处于安全状态是指系统能按某种进程顺序(P1, P2, …, Pn)来为每个进程分配其所需的资源,直至最大需求,使每个进程都可以顺利地完成。
  • 银行家算法 (Banker's Algorithm):这是最著名的死锁避免算法。在分配资源之前,系统会检查这次分配是否会导致系统从安全状态转变为不安全状态。如果是,则不予分配,让进程等待。

3. 死锁检测与解除 (Deadlock Detection and Recovery)

这种策略允许死锁的发生,但系统会不断地监测,判断死锁是否真的发生了。一旦检测出死锁,就会采取措施来解除它。

  • 死锁检测
    • 资源分配图:通过检测资源分配图中是否存在环路来判断是否发生了死锁。 系统会定期运行一个算法来检测这个图。
  • 死锁解除:一旦检测到死锁,可以采取以下措施:
    • 资源剥夺法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。
    • 撤销进程:强制撤销部分甚至全部死锁进程,并剥夺这些进程的资源。
    • 进程回滚:让一个或多个进程回退到足以避免死锁的地步。

4. 忽略死锁

在某些系统中,死锁发生的概率很低,而用于预防、避免或检测和解除死锁的开销又很大。在这种情况下,可以采取“鸵鸟算法”,即假装问题从未发生过。 如果真的发生了死锁,可以通过重启系统来解决。

策略 描述 优点 缺点
死锁预防 通过破坏死锁产生的四个必要条件之一来防止死锁。 简单,从根本上防止死锁。 限制了并发性,降低了资源利用率。
死锁避免 在资源分配时动态判断是否会进入不安全状态,从而避免死锁。 资源利用率较高,不需要预先知道所有资源请求。 需要预知进程的最大资源需求,算法开销较大。
死锁检测与解除 允许死锁发生,但通过检测机制及时发现并采取措施解除。 资源利用率和并发性较高。 检测和解除死锁的开销可能很大。
忽略死锁 假定死锁不会发生,不采取任何措施。 无系统开销。 系统可能因死锁而挂起,需要手动干预(如重启)。