死锁的四个必要条件
1. 死锁产生的四个必要条件
这四个条件是考研的必考点,要求能准确默写、理解,并能结合实例进行分析。
1.1 条件定义与阐述
-
互斥条件 (Mutual Exclusion)
-
含义: 进程所申请的资源是独占的、排他性的,即一个资源在任意时刻只能被一个进程所使用。
-
解释: 这个条件是很多资源的固有属性,比如打印机、物理内存区域等。如果资源本身就是可共享的(如只读文件),那么该资源本身就不会引发死锁。这个条件通常是无法破坏的。
-
-
请求与保持条件 (Hold and Wait)
-
含义: 进程在已经保持了至少一个资源的情况下,又提出了新的资源请求,但该资源已被其他进程占用,此时请求进程被阻塞,但它在等待新资源时并不会释放自己已经保持的资源。
-
解释: 这是资源分配策略上的问题。“拿着碗里的,还看着锅里的”。
-
-
不可剥夺条件 (No Preemption)
-
含义: 进程已获得的资源,在未使用完毕之前,不能被其他进程强行剥夺,只能由获得该资源的进程自己主动释放。
-
解释: 这保证了进程对已分配资源的控制权,但同时也增加了死锁的风险。
-
-
循环等待条件 (Circular Wait)
-
含义: 存在一个进程-资源的循环等待链,即存在一个进程集合
{P_0, P_1, ..., P_n}
,其中 P_0 正在等待 P_1 所占用的资源,P_1 正在等待 P_2 所占用的资源,...,P_n 正在等待 P_0 所占用的资源。 -
解释: 这是死锁状态的直接体现,形成了一个“你等我、我等你”的闭环。可以用“资源分配图”清晰地展示出来,如果图中出现了环路,则可能存在死锁(如果每类资源只有一个实例,则必为死锁)。
-
1.2 实例说明
我们用一个非常经典的例子来说明这四个条件是如何同时出现的。
场景: 系统中有两个进程 P1
、P2
,以及两个互斥资源 R1
(打印机)、R2
(扫描仪)。
执行时序:
-
时刻 t1:
P1
成功申请到资源R1
(打印机)。 -
时刻 t2:
P2
成功申请到资源R2
(扫描仪)。 -
时刻 t3:
P1
在保持R1
的同时,又去申请R2
。但R2
已被P2
占用,因此P1
进入阻塞等待状态。 -
时刻 t4:
P2
在保持R2
的同时,又去申请R1
。但R1
已被P1
占用,因此P2
也进入阻塞等待状态。
此刻,系统进入死锁状态。我们来分析四个条件是否满足:
-
满足互斥条件: 打印机
R1
和扫描仪R2
都是独占设备,一次只能给一个进程使用。 -
满足请求与保持条件:
P1
保持着R1
去请求R2
;P2
保持着R2
去请求R1
。 -
满足不可剥夺条件: 系统不能强行将
R1
从P1
手中夺走分配给P2
,也不能将R2
从P2
手中夺走分配给P1
。 -
满足循环等待条件:
P1
等待P2
释放R2
,而P2
同时在等待P1
释放R1
,形成了P1 -> R2 -> P2 -> R1 -> P1
的循环等待链。
由于四个条件同时满足,死锁发生。两个进程都将永远等待下去,无法推进。
2. 信号量与死锁的关系
这是一个非常经典的考点,也是一个极易产生误解的地方。
明确结论: 使用信号量机制并不能保证不出现死锁。恰恰相反,对信号量的不当使用是导致死锁的常见原因之一。
-
生产者接着执行
P(empty)
。由于empty.value
为0,生产者进程阻塞。关键点:此时它因为阻塞,无法执行后面的V(mutex)
,所以它仍然“保持”着mutex
信号量。 -
此时轮到消费者执行,它想要消费一个产品。
-
消费者执行
P(full)
,成功(因为缓冲区是满的),full.value
减1。 -
消费者接着执行
P(mutex)
,试图进入临界区取出产品。但由于mutex.value
已被生产者置为0,所以消费者进程阻塞。