死锁的定义
一个关于死锁粗浅直观的理解可以看看这个系列之前的文章中相关的部分 :
十天掌握操作系统——进程(0)
关于临界资源的介绍请移步:
十天掌握操作系统——进程(3)进程的并发控制(信号量、PV操作)
死锁:一组进程是死锁的,是指一组进程中的每一个进程都在等待其他进程占用的资源而引发的错误现象
死锁产生的必要条件
-
互斥条件
临界资源一次只允许一个进程使用 -
不剥夺
已经分配给进程的资源不能被剥夺,只能由当前拥有它的进程释放 -
循环等待
存在一个进程循环链,其中每一个进程都在等待下一个进程释放资源*举个例子:进程A需要a,b两个资源,现在已经有a了,还需b(b被B占有);进程B需要b,c,已经有b了,现在还差c(c被C占有);进程C需要a,c,已经有c了,现在还差a(a被A占有);
然后三个进程就形成了一个循环链卡在这里。
- 保持和等待条件
进程因为请求资源而进入阻塞状态的时候,进程拥有的资源不能被释放
死锁产生的原因
- 系统资源配置不足,引起进程竞争资源
- 并发进程请求资源的随机性,包括锁请求的资源的类别和数量
- 各个并发进程在系统中异步向前推进,造成进程推进顺序的不合理
这里的意思是多个进程申请资源的时候并没有一个统筹的安排
上面那个例子中A,B已经占有a,b的情况下,如果有一个“上帝”知道C这个时候申请c会死锁,就让C等一下,先给A用c。
死锁产生的根本原因:对临界资源的共享,并发进程的同步关系不当
解决死锁的办法
鸵鸟算法
就是直接无视,当做不会发生死锁处理。实际中死锁发生的概率甚至比发生硬件故障的概率要低
现在就是这样做的,下面提到的其他办法都只是一个提议,没有真正应用的
死锁的预防
通过破坏死锁产生的必要条件中的一个或者几个条件来预防死锁。但是目前都没有可以实际应用的办法。下面介绍一些破坏这些条件的思路以及他们不太可行的原因。
-
破坏互斥条件:这是资源本身的特性决定的,根本不能破坏。
-
破坏保持和等待条件:
每个进程在执行之前就把锁需要的资源全部申请到,申请不到就不执行。许多进程在运行之前不能精确的提出所用资源的数量。 -
破坏循环等待条件:
将系统中的资源排序。要求进程在申请资源的时候必须按照升序申请。进程申请的下一个资源的编号要大于它上一个申请的资源编号。
如果A进程申请到了编号为 i 的资源,B进程申请到了编号为 j 的资源。i<j 。接下来A可以申请B占有的 j 资源,但是B不可以申请A占有的 i 资源。 -
破坏不剥夺条件:
如果一个进程之前申请到了一些资源,然后在申请其他资源的时候申请不到将进入阻塞,在它阻塞前把它之前申请的资源释放。这样固然可以避免死锁,但是该进程释放资源之后,之后要继续运行的话还是要恢复资源,而且要还原之前进程释放该资源前的使用现场,对操作系统来说代价过于大。但是对于任意一组进程要找到这样的一组序号可以满足进程的运行是比较困难的。
比如 A进程需要依次使用麦克风、摄像头、打印机资源,并且必须按照这个顺序,如果将麦克风、摄像头、打印机的序号依次设置成5,4,3,那A进程在这个规则和序号下就运行不了了。还有可能产生两个进程需要的序号大小顺序冲突。比如A需要麦克风的序号小于摄像头的,但是B需要摄像头小于麦克风。
(正在准备期末考试的同学预防死锁这一段粗略了解即可)
死锁的避免
在分配资源的时候防止系统进入不安全状态来避免死锁。有下面两种方案:
- 进程-资源轨迹图
- 银行家算法
进程-资源轨迹图
详见《操作系统原理教程》。之后填坑。
银行家算法
Dijkstra在1965年提出银行家算法。
有四个顾客:A,B,C,D,每个顾客提出的最大贷款数量分别为6、5、4、7(以千美元为单位)。
银行家知道不是所有顾客都马上需要其全部贷款(22)。
因此,他只保留10个单位数量(而不是全部22个单位)为这些顾客服务。
在这个模型中,顾客是进程,现金是资源,而银行家就是操作系统。
安全状态下,能够找到一个用户,他的(最大要求量-拥有量)<= 当前剩余量。 在b中是顾客C。
不安全状态就是 找不到这么一个顾客的时候。(这里的安全是某个时刻下的安全,下面提到的安全是之后都会安全)
在银行家算法中每次即将给一个进程分配资源的时候,都会先看看把资源分配给这个进程之后,还能不能找到一个进程完成序列。如果可以那么就把资源给这个进程,如果不可以,让其阻塞等待。
找到一种资源分配的方案使得最后所有进程都可以顺利完成而不发生死锁,在这种方案下,多个进程会依次结束执行,这个结束执行的先后次序就是进程完成次序。
说白了就像下棋的时候落一颗子,犹豫要不要落在这个地方,那就假设落在这个地方,然后去推演之后棋局的发展,如果最后有一种局面可以赢,那就决定下这里。
上面的银行家问题只介绍了只有一种资源的情况。如果有多种不同的资源,安全状态则是:能够找到一个进程,对于每一种资源它的最大要求减去拥有量的值(即剩余请求量) <= 这种资源的当前剩余量。
用一个例子详细说明:
同时还有一个Avail(当前剩余资源量向量) = (1,0,2,0) (磁带机剩下1个,绘图机剩0…)
判断当前是不是安全的:找Need矩阵里面有没有一行,这一行中的每一列都比Avail小
第四行满足,所以现在是安全的
死锁的检测和恢复
允许死锁发生。通过设置特定的死锁检测机制检测死锁的发生。及时采取措施清除死锁。
死锁的检测
用进程资源图检测死锁
如果进程资源图里面包含有一个或者多个环路,则说明存在死锁,否则说明不存在死锁。
圆圈代表资源,方块代表进程
下图代表进程B已经占有资源b
下图代表进程A正在申请资源a
含有环路即发生死锁
A 拥有b,需要a,但是a被B占有;B拥有a,需要b, 但是b被A占有
死锁的恢复
- 故障终止进程
可以一次性终止所有死锁进程,也可以一次终止一个死锁进程直到死锁解除。 - 剥夺资源
- 抢走一些进程的资源给其他进程使用
- 把被抢走资源的进程回退到获得资源之前的状态