死锁的四个必要条件

1. 死锁产生的四个必要条件

这四个条件是考研的必考点,要求能准确默写、理解,并能结合实例进行分析。

1.1 条件定义与阐述

  1. 互斥条件 (Mutual Exclusion)

    • 含义: 进程所申请的资源是独占的、排他性的,即一个资源在任意时刻只能被一个进程所使用。

    • 解释: 这个条件是很多资源的固有属性,比如打印机、物理内存区域等。如果资源本身就是可共享的(如只读文件),那么该资源本身就不会引发死锁。这个条件通常是无法破坏的。

  2. 请求与保持条件 (Hold and Wait)

    • 含义: 进程在已经保持了至少一个资源的情况下,又提出了新的资源请求,但该资源已被其他进程占用,此时请求进程被阻塞,但它在等待新资源时并不会释放自己已经保持的资源。

    • 解释: 这是资源分配策略上的问题。“拿着碗里的,还看着锅里的”。

  3. 不可剥夺条件 (No Preemption)

    • 含义: 进程已获得的资源,在未使用完毕之前,不能被其他进程强行剥夺,只能由获得该资源的进程自己主动释放。

    • 解释: 这保证了进程对已分配资源的控制权,但同时也增加了死锁的风险。

  4. 循环等待条件 (Circular Wait)

    • 含义: 存在一个进程-资源的循环等待链,即存在一个进程集合 {P_0, P_1, ..., P_n},其中 P_0 正在等待 P_1 所占用的资源,P_1 正在等待 P_2 所占用的资源,...,P_n 正在等待 P_0 所占用的资源。

    • 解释: 这是死锁状态的直接体现,形成了一个“你等我、我等你”的闭环。可以用“资源分配图”清晰地展示出来,如果图中出现了环路,则可能存在死锁(如果每类资源只有一个实例,则必为死锁)。

1.2 实例说明

我们用一个非常经典的例子来说明这四个条件是如何同时出现的。

场景: 系统中有两个进程 P1P2,以及两个互斥资源 R1(打印机)、R2(扫描仪)。

执行时序:

  1. 时刻 t1: P1 成功申请到资源 R1(打印机)。

  2. 时刻 t2: P2 成功申请到资源 R2(扫描仪)。

  3. 时刻 t3: P1 在保持 R1 的同时,又去申请 R2。但 R2 已被 P2 占用,因此 P1 进入阻塞等待状态。

  4. 时刻 t4: P2 在保持 R2 的同时,又去申请 R1。但 R1 已被 P1 占用,因此 P2 也进入阻塞等待状态。

此刻,系统进入死锁状态。我们来分析四个条件是否满足:

由于四个条件同时满足,死锁发生。两个进程都将永远等待下去,无法推进。

2. 信号量与死锁的关系

这是一个非常经典的考点,也是一个极易产生误解的地方。

明确结论: 使用信号量机制并不能保证不出现死锁。恰恰相反,对信号量的不当使用是导致死锁的常见原因之一。

  1. 生产者接着执行 P(empty)。由于 empty.value 为0,生产者进程阻塞关键点:此时它因为阻塞,无法执行后面的 V(mutex),所以它仍然“保持”着 mutex 信号量。

  2. 此时轮到消费者执行,它想要消费一个产品。

  3. 消费者执行 P(full),成功(因为缓冲区是满的),full.value 减1。

  4. 消费者接着执行 P(mutex),试图进入临界区取出产品。但由于 mutex.value 已被生产者置为0,所以消费者进程阻塞