一、什么是死锁?
死锁是指两个(或多个)线程互相等待对方数据的过程,死锁的产生导致程序卡死,不解锁程序将永远⽆法进⾏下 去
二、死锁产生条件
死锁只有同时满足以下四个条件才会发生:互斥条件;持有并等待条件;不可剥夺条件;
环路等待条件。
1. 互斥条件
进程对所需求的资源具有排他性,若有其他进程请求该资源,请求进程只能等待。
2. 持有并等待条件
进程当前所拥有的资源在进程请求其他新资源时,由该进程继续占有。
3. 不可剥夺条件
进程在所获得的资源未释放前,不能被其他进程强行夺走,只能自己释放。
- 可抢占资源:可以从拥有它的进程中抢占而不会产⽣任何副作用,存储器就是⼀类可抢占资源。
- 不可抢占资源:指在不引起相关计算失败的情况下,无法把它从占有它的进程处抢占过来。
4. 环路等待条件
存在⼀种进程资源循环等待链,链中每个进程已获得的资源同时被链中下⼀个进程所请求。
三、如何预防死锁?
1. 破坏互斥条件
例如假脱机打印机技术允许若干个进程同时输出,唯⼀真正请求物理打印机的进程是打印机守护进程。
2. 破坏请求和保持条件
⼀种实现方式是规定所有进程在开始执行前请求所需要的全部资源。
3. 破坏不剥夺条件
允许抢占资源
4. 破坏循环请求等待
给资源统⼀编号,进程只能按编号顺序来请求资源。
四、发现死锁如何处理?
1. 鸵鸟策略
把头埋在沙子里,假装根本没发生问题。 因为解决死锁问题的代价很高,因此鸵鸟算法这种不采取任务措施的方案会获得更高的性能。 当发生死锁时不会对用户造成很大影响,或发生死锁的概率很低,可以采用鸵鸟算法。大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。
2. 死锁检测与死锁恢复
不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。
(1)每种类型⼀个资源的死锁检测
通过检测有向图中是否存在环来实现,从⼀个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁发生。
(2)每种类型多个资源的死锁检测
每个进程最开始时都不被标记,执行过程有可能被标记。当算法结束时,任何没有被标记的进程都是死锁进程。
- 寻找⼀个没有标记的进程Pi,它所请求的资源小于或等于 A ;
- 如果真找到这样⼀个进程,那么将C矩阵的第 i 行向量加到 A 中,标记该进程,并转回第1步;
- 如果没有这样的进程,那么算法终止。
举个🌰:
上图中,有三个进程四个资源,每个数据代表的含义如下:
- E 向量:资源总量
- A 向量:资源剩余量
- C矩阵:每个进程所拥有的资源数量,每一行都代表一个进程拥有资源的数量
- R 矩阵:每个进程请求的资源数量
进程 P1 和 P2 所请求的资源都得不到满足,只有进程 P3 可以,让 P3 执⾏,之后释放 P3 拥有的资源,此时 A = (2 2 2 0)。P2 可以执⾏,执⾏后释放 P2 拥有的资源,A = (4 2 2 1) 。P1 也可以执⾏。所有进程都可以顺利执⾏,没有死锁。
检测到死锁之后,可以采用以下方法进行恢复:
- 利用抢占恢复 将进程挂起,强⾏取走资源给另⼀个进程使用,用完再放回
- 利用回滚恢复 复位到更早的状态,那时它还没有取得所需的资源
- 通过杀死进程恢复 杀掉环中的⼀个进程或多个,牺牲掉⼀个环外进程
五、程序运行中如何避免死锁?
安全状态:如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能够使得每⼀个进程运行完毕,则称该状态是安全的。
Has 表示已拥有的资源数,Max 表示总共需要的资源数,Free 表示还有可以使⽤的资源数。
从图 a 开始出发,先让 B 拥有所需的所有资源(图 b),运行结束后释放 B,此时 Free 变为 5(图 c);接着以同样的方式运行 C 和 A,使得所有进程都能成功运行,因此可以称图 a 所示的状态时安全的。
安全状态的检测与死锁的检测类似,因为安全状态必须要求不能发生死锁。下面的银行家算法与死锁检测算法非常类似,可以结合着做参考对对比。
(1)单个资源的银行家算法
一个小城镇的银行家,他向⼀群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。
(2)多个资源的银行家算法
- 查找是否存在所需资源矩阵(Max-Has)小于等于资源剩余量A的进程。如果不存在这样的行,那么系统将会发生死锁,状态是不安全的。
- 假若找到这样的进程,将该进程标记为终止,并将其已分配资源加到 A 中。
- 重复以上两步,直到所有进程都标记为终止,则状态时安全的。 如果一个状态不是安全的,需要拒绝进入这个状态。