在多道程序环境中,多个进程可以竞争有限数量的资源。当一个进程申请资源时,如果这时没有可用资源,那么这个进程进入等待状态。有时,如果所申请的资源被其他等待进程占有, 那么该等待进程有可能再也无法改变状态。这种情况称为死锁(deadlock) 。
5.1 系统模型
系统拥有有限数量的资源,需要分配到多个竞争进程。即多进程对共享资源的竞争可能导致死锁。
在正常模式下,进程只能按如下顺序使用资源:
1. 申请: 进程请求资源。如果申请不能立即被允许,那么申请进程应等待,直到它能获得该资源为止。
2. 使用: 进程对资源进行操作。
3. 释放: 进程释放资源。
5.2 死锁特征
当死锁时,进程永远不能完成,系统资源被阻塞使用,以致于阻止了其他作业的开始执行。
5.2.1 死锁的必要条件
如果在一个系统中以下四个条件同时成立,那么就能引起死锁:
- 互斥(mutual exclusion) :至少有一个资源必须处于非共享模式, 即一次只有一个进程可使用。如果另一进程申请该资源,那么申请进程应等到该资源释放为止。
- 占有并等待(hold and wait) :一个进程应占有至少一个资源, 并等待另一个资源, 而该资源为其他进程所占有。
- 非抢占(no preemption) : 资源不能被抢占,即资源只能被进程在完成任务后自愿释放。
- 循环等待(circular wait) :有一组等待进程{
P
0
P_0
P0,
P
1
P_1
P1, ……,
P
n
P_n
Pn} ,
P
0
P_0
P0等待的资源为
P
1
P_1
P1占有,
P
0
P_0
P0等待的资源为
P
2
P_2
P2占有,……,
P
n
P_n
Pn等待的资源为
P
0
P_0
P0占有。
我们强调所有四个条件必须同时成立才会出现死锁。
循环等待条件意味着占有并等待条件,这样四个条件并不完全独立。
5.3 死锁预防
发生死锁有4个必要条件。只要确保至少一个必要条件不成立,就能预防死锁发生。
5.3.1 互斥
互斥条件必须成立。也就是说,对共享资源的互斥申请。相反,可共享资源不要求互斥访问,因此不会死锁。比如,只读文件是一个很好的共享资源的例子。
5.3.2 持有且等待
为了确保持有并等待条件不会出现在系统中,应保证:当每个进程申请一个资源时,它不能占有其他资源。
一种可以采用的协议是,每个进程在执行前申请并获得所有资源。这可以这样实现:要求进程申请资源的系统调用在所有其他系统调用之前进行。
另外一种协议允许进程仅在没有资源时才可申请资源。一个进程可申请一些资源并使用它们。然而,在它申请更多其他资源之前,它应释放现已分配的所有资源。
这两种协议有两个主要缺点:
第一,资源利用率可能比较低,因为许多资源可能已分配,但是很长时间没有被使用。
第二,可能发生饥饿。一个进程如需要多个常用资源,可能必须永久等待,因为在它所需要的资源中至少有一个已分配给其他进程。
5.3.3 无抢占
不能抢占已分配的资源。为了确保这一条件不成立,可以采用如下协议:如果一个进程持有资源并申请另一个不能立即分配的资源(也就是说,这个进程应等待),那么它现在分配的资源都可被抢占。
换句话说,这些资源都被隐式释放了。被抢占资源添加到进程等待的资源列表上。只有当进程获得其原有资源和申请的新资源时,它才可以重新执行。
换句话说,如果一个进程申请一些资源,那么首先检查它们是否可用。如果可用,那么就分配它们。如果不可用,那么检查这些资源是否已分配给等待额外资源的其他进程。如果是,那么从等待进程中抢占这些资源,并分配给申请进程。如果资源不可用且也不被其他等待进程持有,那么申请进程应等待。当一个进程处于等待时,如果其他进程申请其拥有资源,那么该进程的部分资源可以被抢占。只有当一个进程分配到申请的资源,并且恢复在等待时被抢占的资源时,它才能重新执行。这个协议通常用于状态可以保存和恢复的资源, 如CPU寄存器和内存。它一般不适用于其他资源,如互斥锁和信号量。
5.3.4 循环等待
确保这个条件不成立的方法是:对所有资源类型进行完全排序,且要求每个进程按递增顺序来申请资源。
5.4 死锁恢复
当检测算法确定已有死锁时,存在多种可选方案。一种可能是,通知操作员死锁已发生, 并且让操作员人工处理死锁。另一种可能是, 让系统从死锁状态中自动恢复(recover)过来。
打破死锁有两个选择。一个是,简单地中止一个或多个进程来打破循环等待。另一个是,从一个或多个死锁进程那里抢占一个或多个资源。