【面试八股总结】死锁:产生条件、预防死锁、处理死锁、避免死锁

一、什么是死锁?

死锁是指两个(或多个)线程互相等待对方数据的过程,死锁的产生导致程序卡死,不解锁程序将永远⽆法进⾏下 去

二、死锁产生条件

死锁只有同时满足以下四个条件才会发生:互斥条件;持有并等待条件;不可剥夺条件;

环路等待条件。

1. 互斥条件

进程对所需求的资源具有排他性,若有其他进程请求该资源,请求进程只能等待。

2. 持有并等待条件

进程当前所拥有的资源在进程请求其他新资源时,由该进程继续占有。

3. 不可剥夺条件

进程在所获得的资源未释放前,不能被其他进程强行夺走,只能自己释放。

  • 可抢占资源:可以从拥有它的进程中抢占而不会产⽣任何副作用,存储器就是⼀类可抢占资源。
  • 不可抢占资源:指在不引起相关计算失败的情况下,无法把它从占有它的进程处抢占过来。

4. 环路等待条件

存在⼀种进程资源循环等待链,链中每个进程已获得的资源同时被链中下⼀个进程所请求。

三、如何预防死锁?

1. 破坏互斥条件

例如假脱机打印机技术允许若干个进程同时输出,唯⼀真正请求物理打印机的进程是打印机守护进程。

2. 破坏请求和保持条件

⼀种实现方式是规定所有进程在开始执行前请求所需要的全部资源。

3. 破坏不剥夺条件

允许抢占资源

4. 破坏循环请求等待

给资源统⼀编号,进程只能按编号顺序来请求资源。

四、发现死锁如何处理?

1. 鸵鸟策略

把头埋在沙子里,假装根本没发生问题。 因为解决死锁问题的代价很高,因此鸵鸟算法这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成很大影响,或发生死锁的概率很低,可以采用鸵鸟算法。大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。

**2.**死锁检测与死锁恢复

不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。

(1)每种类型⼀个资源的死锁检测

通过检测有向图中是否存在环来实现,从⼀个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁发生。

(2)每种类型多个资源的死锁检测

每个进程最开始时都不被标记,执行过程有可能被标记。当算法结束时**,任何没有被标记的进程都是死锁进程。**

  1. 寻找⼀个没有标记的进程Pi,它所请求的资源小于或等于 A ;
  2. 如果真找到这样⼀个进程,那么将C矩阵的第 i 行向量加到 A 中,标记该进程,并转回第1步;
  3. 如果没有这样的进程,那么算法终止。

举个🌰:

上图中,有三个进程四个资源,每个数据代表的含义如下:

  • 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)多个资源的银行家算法

  1. 查找是否存在所需资源矩阵(Max-Has)小于等于资源剩余量A的进程。如果不存在这样的行,那么系统将会发生死锁,状态是不安全的。
  2. 假若找到这样的进程,将该进程标记为终止,并将其已分配资源加到 A 中。
  3. 重复以上两步,直到所有进程都标记为终止,则状态时安全的。 如果一个状态不是安全的,需要拒绝进入这个状态。
相关推荐
Lee川3 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i5 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
chlk1235 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
绝无仅有5 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有6 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫7 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫7 小时前
Handler基本概念
面试
Wect7 小时前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼8 小时前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼8 小时前
Next.js 企业级落地
前端·javascript·面试