870 lines
38 KiB
Markdown
870 lines
38 KiB
Markdown
# 第五章 死锁与饥饿
|
||
|
||
## 一、知识讲解
|
||
|
||
本章是操作系统的**核心重点章节**,每年必考**大题**(银行家算法、安全性算法、资源分配图)。死锁(Deadlock)与饥饿(Starvation)都是**进程竞争资源**引起的问题,但本质上不同:死锁是"等不到",饥饿是"等太久"。
|
||
|
||
---
|
||
|
||
### 5.1 死锁的概念
|
||
|
||
#### 5.1.1 死锁定义
|
||
|
||
**死锁(Deadlock)**:一组进程中的每一个进程,均**无限期地等待**此组进程中某个**其他进程**所占有的、因而**永远无法得到**的资源,这种现象称为进程死锁。
|
||
|
||
通俗理解:进程A等进程B手里的资源,进程B又在等进程A(或C、D……)手里的资源,环上谁也得不到谁手里的资源,所有人无限等待。
|
||
|
||
**死锁发生的两个时刻**:
|
||
1. **无限等待发生时**(事后观察)
|
||
2. **等待发生前**——已注定死锁(事前预测,如银行家算法拒绝分配就是"提前避免")
|
||
|
||
#### 5.1.2 由定义得出的结论
|
||
|
||
1. 参与死锁的进程**至少有 2 个**。
|
||
2. 每个参与死锁的进程**均处于等待资源的状态**。
|
||
3. 参与死锁的进程中**至少有两个进程已经占有资源**(否则大家都空手等不到资源,但若没人占有资源则不构成"等待别人资源"的定义)。
|
||
4. 死锁进程是系统中当前进程集合的一个**子集**(不是全部进程)。
|
||
|
||
---
|
||
|
||
### 5.2 死锁的类型
|
||
|
||
#### 1. 资源竞争引起的死锁(最常见)
|
||
|
||
- **(1)不同资源类**:每个进程分别占有对方需要的资源。例如 P1 占有 R1 等 R2,P2 占有 R2 等 R1。
|
||
- **(2)同种资源**:多个进程反复申请同类资源(如 4 台打印机),P1 申请 8 次每次申请 1 个,P2 申请 4 次每次申请 1 个。**典型问题:信号量/缓冲区的死锁**。
|
||
|
||
举例:4 台打印机,P1 的命令序列为 `a a a a a a a a`(申请 8 次),P2 的命令序列为 `a a a a`(申请 4 次)。当 P1 占 3 台、P2 占 1 台时,P1 还需 5 台,P2 还需 3 台——总需 8 台 > 4 台,**永久等待**。
|
||
|
||
#### 2. 进程通讯引起的死锁(消息通信)
|
||
|
||
```
|
||
P1: receive(P2, M1);
|
||
P2: receive(P3, M2);
|
||
P3: receive(P1, M3);
|
||
```
|
||
三人各等对方先发消息,**谁也等不到**,构成死锁。
|
||
|
||
#### 3. 其它原因
|
||
|
||
- **"After you / After you" 现象**:互相礼让导致谁也不前进(类似**活锁**)。
|
||
- 进程推进顺序不当(如未按资源序申请)。
|
||
|
||
---
|
||
|
||
### 5.3 死锁的条件(Coffman 条件,必要条件)
|
||
|
||
**死锁发生的四个必要条件(Coffman 条件)**:
|
||
|
||
| 条件 | 英文 | 含义 | 举例 |
|
||
|------|------|------|------|
|
||
| **互斥使用(资源独占)** | Mutual Exclusion | 资源一次只允许一个进程使用 | 打印机、临界资源 |
|
||
| **不可抢占(不可剥夺)** | Non-preemption | 资源只能由占有者自愿释放,不能被强制夺走 | 打印机已打印一半不能抢走 |
|
||
| **保持申请(占有并等待)** | Hold-and-Wait | 进程在保持已有资源的同时再去申请新资源 | 进程已占打印机又申请磁带机 |
|
||
| **循环等待(环路等待)** | Circular Wait | 存在进程资源环路,P1等P2、P2等P3、……、Pn等P1 | 经典环路死锁 |
|
||
|
||
**重要结论**:
|
||
- 当每类资源**只有一个实例**时,这四个条件是**充要条件**(有环就一定死锁)。
|
||
- **破坏其中任意一个条件即可消除死锁**(这是死锁预防的理论基础)。
|
||
|
||
---
|
||
|
||
### 5.4 死锁的处理(处理策略总览)
|
||
|
||
处理死锁有 4 种主要策略,下表对比:
|
||
|
||
| 策略 | 英文 | 思想 | 时机 | 难度/开销 |
|
||
|------|------|------|------|----------|
|
||
| **死锁预防** | Deadlock Prevention | 静态地破坏 4 个必要条件之一 | 运行前 | 实现简单但资源利用率低 |
|
||
| **死锁避免** | Deadlock Avoidance | 动态地保证系统始终处于安全状态 | 每次分配前 | 银行家算法,需预知最大需求 |
|
||
| **死锁检测** | Deadlock Detection | 允许死锁发生,但定期检测 | 运行时 | 检测后需恢复 |
|
||
| **死锁恢复** | Deadlock Recovery | 检测到死锁后采取措施 | 死锁发生后 | 终止进程或剥夺资源 |
|
||
| **鸵鸟算法** | Ostrich Algorithm | 忽略不管 | —— | 最省事,实际系统多用 |
|
||
|
||
---
|
||
|
||
### 5.5 资源分配图(Resource Allocation Graph)
|
||
|
||
#### 5.5.1 资源分配图定义
|
||
|
||
**资源分配图**:G = (V, E)
|
||
- V = P ∪ R(进程集合 ∪ 资源集合)
|
||
- E = 申请边 ∪ 分配边
|
||
|
||
**两类节点**:
|
||
- **进程节点 pi**(用圆圈表示)
|
||
- **资源节点 rj**(用方框表示,方框内的圆点表示实例个数)
|
||
|
||
**两类边**:
|
||
- **申请边 (pi, rj)**:由进程指向资源类,表示 pi 申请 rj 中一个实例
|
||
- **分配边 (rj, pi)**:由资源实例指向进程,表示该实例已分配给 pi
|
||
|
||
**操作规则**:
|
||
- **申请**:pi 申请 rj 时,由 pi 向 rj 画一条申请边;若系统满足申请,则将该边改为分配边。
|
||
- **释放**:删除分配边。
|
||
|
||
#### 5.5.2 资源分配图的约简(化简)
|
||
|
||
**约简算法**(判断有无死锁):
|
||
1. 寻找一个**非孤立**且**没有请求边**的进程节点 pi。若不存在这样的节点且仍有非孤立节点,**算法结束**(图中必有环且环上无符合条件的进程)。
|
||
2. 去除 pi 的**所有分配边**,使其成为孤立节点。
|
||
3. 寻找所有请求边都可满足的进程 pj,将 pj 的所有请求边全部改为分配边(视为可立即满足)。
|
||
4. 转步骤 1。
|
||
|
||
**死锁定理**:
|
||
- 若算法结束时**所有节点均为孤立节点**,则称资源分配图是**完全可约简的**。
|
||
- 否则称为**不可完全约简的**。
|
||
- **死锁定理**:S 状态为死锁状态的**充分必要条件**是 S 的资源分配图**不可完全约简**。
|
||
|
||
#### 5.5.3 资源分配图典型例子
|
||
|
||
**例 1**:无环路,无死锁。
|
||
|
||
**例 2**:有环路,有死锁(每类资源只有一个实例时)。
|
||
|
||
**例 3**:有环路,无死锁(某类资源有多个实例):
|
||
- 即使存在环路,**环外有空闲实例**,环路上的进程仍可能获得资源继续运行,最终环路会消失。
|
||
- 关键判据:**约简成功则不死锁,约简失败则死锁**。
|
||
|
||
**易错点**:有环不等于死锁;只有**环上每个资源类只有一个实例**时,有环才等价于死锁。
|
||
|
||
---
|
||
|
||
### 5.6 死锁预防
|
||
|
||
思想:**对进程有关资源的活动加限制**,所有进程遵守即可保证不死锁。
|
||
- 优点:简单,系统不需要做什么。
|
||
- 缺点:对进程的约束太强,资源利用率低;若进程违反约束仍可能死锁。
|
||
|
||
#### 5.6.1 预先分配法
|
||
|
||
- **进程**:运行前一次性申请所需全部资源。
|
||
- **系统**:能全满足则全分配;否则**一个也不分配**,进程等待。
|
||
|
||
**破坏条件**:破坏"hold-and-wait"(保持申请)条件。
|
||
**缺点**:
|
||
- 资源利用效率低(资源被长时间占用)。
|
||
- 进程难以事先知道自己所需全部资源。
|
||
|
||
#### 5.6.2 有序分配法
|
||
|
||
- 给资源集 R = {r1, r2, ..., rn} 定义一个函数 **F: R → N**(给每个资源类一个唯一编号)。
|
||
- 进程 pi 申请资源 rj 中实例的**前提**:∀ 占有的资源 rl,F(rl) < F(rj)。
|
||
- 即**先申请小编号资源,再申请大编号资源**。
|
||
|
||
**无死锁证明**(反证法):
|
||
假设死锁,存在环路:
|
||
- t1:p1 等待 rk1(被 p2 占有)
|
||
- t2:p2 等待 rk2(被 p3 占有)
|
||
- …
|
||
- tn:pn 等待 rkn(被 p1 占有)
|
||
|
||
按有序申请假设:F(rk1) < F(rk2) < ... < F(rkn) < F(rk1) — **矛盾**!
|
||
|
||
**优点**:与预先分配法相比,资源利用率提高。
|
||
**缺点**:
|
||
- 资源编号困难(人为规定顺序)。
|
||
- 为保持按序申请,某些暂时不用的资源也需提前申请,仍牺牲资源利用率。
|
||
|
||
#### 5.6.3 死锁预防策略对比
|
||
|
||
| 方法 | 破坏条件 | 评价 |
|
||
|------|----------|------|
|
||
| 预先分配 | 保持申请 | 资源利用率最低,几乎不可用 |
|
||
| 有序分配 | 循环等待 | 实用但需事先定序 |
|
||
|
||
---
|
||
|
||
### 5.7 死锁避免——银行家算法(Banker's Algorithm)
|
||
|
||
#### 5.7.1 基本思想
|
||
|
||
由 Dijkstra 提出。**核心思想**:每次资源分配前,模拟分配后是否仍能找到一条**安全进程序列**,能则分配,不能则拒绝。
|
||
|
||
#### 5.7.2 安全状态与安全序列
|
||
|
||
- **安全状态**:存在一个进程序列 ⟨p1, p2, ..., pn⟩,按照此序列分配资源,每个进程都能顺利完成。
|
||
- **不安全状态**:不存在这样的安全序列。**不安全状态不一定立即死锁,但终将死锁**。
|
||
|
||
#### 5.7.3 银行家算法的数据结构
|
||
|
||
设 n 个进程 p1..pn,m 类资源 r1..rm:
|
||
|
||
| 数据结构 | 类型 | 含义 |
|
||
|---------|------|------|
|
||
| **Available** | array[1..m] of integer | 系统当前可用资源数 |
|
||
| **Claim / Max** | array[1..n, 1..m] of integer | 进程最大需求(事先申明) |
|
||
| **Allocation** | array[1..n, 1..m] of integer | 已分配给进程的资源 |
|
||
| **Need** | array[1..n, 1..m] of integer | 进程还需要的资源 = Claim − Allocation |
|
||
| **Request[i]** | array[1..m] of integer | 进程 pi 当前请求 |
|
||
|
||
临时变量:
|
||
- **Work** = Available(安全性算法中模拟可用资源)
|
||
- **Finish** = array[1..n] of boolean
|
||
|
||
**符号约定**:
|
||
- X ≤ Y ⟺ ∀j, X[j] ≤ Y[j]
|
||
- X := Y、 X := c(向量赋值)等按分量进行。
|
||
|
||
#### 5.7.4 银行家算法(资源分配主流程)
|
||
|
||
```
|
||
进程 pi 请求资源 Request[i]:
|
||
|
||
1. 若 Request[i] > Need[i]:报错(超出最大需求)。
|
||
2. 若 Request[i] > Available:pi 必须等待。
|
||
3. 系统试探分配:
|
||
Available := Available − Request[i]
|
||
Allocation[i] := Allocation[i] + Request[i]
|
||
Need[i] := Need[i] − Request[i]
|
||
4. 执行安全性算法:
|
||
若新状态安全 → 真正分配,pi 继续。
|
||
若不安全 → 撤销试探分配,pi 等待。
|
||
```
|
||
|
||
#### 5.7.5 安全性算法(Safety Algorithm)
|
||
|
||
```
|
||
输入:Available, Allocation, Need
|
||
输出:是否存在安全序列
|
||
|
||
1. Work := Available
|
||
Finish[i] := false, ∀i
|
||
|
||
2. 寻找满足下列条件的 i:
|
||
Finish[i] = false 且 Need[i] ≤ Work
|
||
若找不到,转 4。
|
||
|
||
3. Work := Work + Allocation[i]
|
||
Finish[i] := true
|
||
转 2。
|
||
|
||
4. 若 ∀i, Finish[i] = true → 安全;
|
||
否则 → 不安全(含死锁可能)。
|
||
```
|
||
|
||
**安全序列的寻找**:每轮挑选一个"尚需资源 ≤ 当前可用"的进程,假设它跑完后归还全部资源,再扩大 Work,继续找下一个。
|
||
|
||
#### 5.7.6 银行家算法完整例题
|
||
|
||
> **例题**:R = {A(10), B(5), C(7)},P = {p0, p1, p2, p3, p4}。
|
||
> 初始快照如下:
|
||
>
|
||
> | 进程 | Claim (A B C) | Allocation (A B C) | Need (A B C) | Available (A B C) |
|
||
> |------|---------------|--------------------|---------------|--------------------|
|
||
> | p0 | 7 5 3 | 0 1 1 | 7 4 2 | 3 3 3 |
|
||
> | p1 | 3 2 2 | 2 0 0 | 1 2 2 | |
|
||
> | p2 | 9 0 2 | 3 0 0 | 6 0 2 | |
|
||
> | p3 | 2 2 2 | 2 1 1 | 0 1 1 | |
|
||
> | p4 | 4 3 3 | 0 0 2 | 4 3 1 | |
|
||
|
||
**步骤 1:安全性检查(初始状态)**
|
||
|
||
Work = (3,3,3),Finish = (F,F,F,F,F)
|
||
|
||
- p3:Need(0,1,1) ≤ Work(3,3,3) ✓,选 p3。Work := (3,3,3)+(2,1,1)=(5,4,4),Finish[p3]=T
|
||
- p1:Need(1,2,2) ≤ Work(5,4,4) ✓,选 p1。Work := (5,4,4)+(2,0,0)=(7,4,4),Finish[p1]=T
|
||
- p4:Need(4,3,1) ≤ Work(7,4,4) ✓,选 p4。Work := (7,4,4)+(0,0,2)=(7,4,6),Finish[p4]=T
|
||
- p2:Need(6,0,2) ≤ Work(7,4,6) ✓,选 p2。Work := (7,4,6)+(3,0,0)=(10,4,6),Finish[p2]=T
|
||
- p0:Need(7,4,2) ≤ Work(10,4,6) ✓,选 p0。Work := (10,4,6)+(0,1,1)=(10,5,7),Finish[p0]=T
|
||
|
||
**安全进程序列:⟨p3, p1, p4, p2, p0⟩**,系统**安全**。
|
||
|
||
**步骤 2:p2 请求 Request[2] = (1, 0, 2)**
|
||
|
||
1. Request[2] = (1,0,2) ≤ Need[2] = (6,0,2) ✓
|
||
2. Request[2] = (1,0,2) ≤ Available(3,3,3) ✓
|
||
3. 试探分配:
|
||
- Available := (3,3,3)−(1,0,2) = (2,3,1)
|
||
- Allocation[2] := (3,0,0)+(1,0,2) = (4,0,2)
|
||
- Need[2] := (6,0,2)−(1,0,2) = (5,0,0)
|
||
4. 安全性检查:
|
||
|
||
| 进程 | Need (A B C) | Allocation (A B C) | Work (A B C) | Finish |
|
||
|------|--------------|--------------------|--------------|--------|
|
||
| 初始 | — | — | 2 3 1 | F,F,F,F,F |
|
||
| p3 | 0 1 1 | 2 1 1 | 2 3 1 ✓ → 4 4 2 | T |
|
||
| p1 | 1 2 2 | 2 0 0 | 4 4 2 ✓ → 6 4 2 | T |
|
||
| p4 | 4 3 1 | 0 0 2 | 6 4 2 ✓ → 6 4 4 | T |
|
||
| p0 | 7 4 3 | 0 1 0 | 6 4 4 ✗ | F |
|
||
| p2 | 5 0 0 | 4 0 2 | 6 4 4 ✓ → 10 4 6 | T |
|
||
| p0 | 7 4 3 | 0 1 0 | 10 4 6 ✓ → 10 5 6 | T |
|
||
|
||
**安全进程序列:⟨p3, p1, p4, p2, p0⟩**,安全。**真正分配**给 p2。
|
||
|
||
**步骤 3:p4 请求 Request[4] = (3, 3, 0)**
|
||
|
||
- Request[4] = (3,3,0) > Available(2,3,1),**不能满足,p4 等待**。
|
||
|
||
**步骤 4:p0 请求 Request[0] = (0, 2, 0)**
|
||
|
||
1. Request[0] = (0,2,0) ≤ Need[0] = (7,4,3) ✓
|
||
2. Request[0] = (0,2,0) ≤ Available(2,3,1) ✓
|
||
3. 试探分配:
|
||
- Available := (2,3,1)−(0,2,0) = (2,1,1)
|
||
- Allocation[0] := (0,1,0)+(0,2,0) = (0,3,0)
|
||
- Need[0] := (7,4,3)−(0,2,0) = (7,2,3)
|
||
4. 安全性检查:
|
||
|
||
| 进程 | Need (A B C) | Allocation (A B C) | Work (A B C) |
|
||
|------|--------------|--------------------|--------------|
|
||
| 初始 | — | — | 2 1 1 |
|
||
| p1 | 1 2 2 | 2 0 0 | 2 1 1 ✗ |
|
||
| p3 | 0 1 1 | 2 1 1 | 2 1 1 ✗ |
|
||
| p4 | 4 3 1 | 0 0 2 | 2 1 1 ✗ |
|
||
| p0 | 7 2 3 | 0 3 0 | 2 1 1 ✗ |
|
||
| p2 | 5 0 0 | 4 0 2 | 2 1 1 ✗ |
|
||
|
||
找不到可满足的进程,**不安全!撤销试探分配,p0 等待**。
|
||
|
||
#### 5.7.7 银行家算法的局限性(保守性)
|
||
|
||
> **例**:R = {A(1), B(1)},P = {p1, p2}。p1: a b;p2: b a a b;Available = (1,1)。
|
||
>
|
||
> - Allocation 全 0,Need = (1,1)/(1,1)。
|
||
> - p1 申请 Request[1] = (1,0),试探分配后 p1 拿 A。p1 还需 B,可从 Available (0,1) 拿到,p1 完成释放 (1,1);再给 p2。**安全,分配**。
|
||
> - p2 申请 Request[2] = (0,1),试探分配后 p2 拿 B。p2 还需 A,但 Available 为 (1,0),p1 还需 B。可 p1 拿 B 完成释放后给 p2,p2 完成。**实际上是安全的**,但银行家算法可能因找不到简单路径而**误判不安全**。
|
||
>
|
||
> 银行家算法是**充要条件**,但需要"进程给出完整命令序列"才能做到 NP 完全级精确。仅按最大需求判断时是**充分不必要**的——**保守**(可能错杀合法分配)。
|
||
|
||
#### 5.7.8 Remarks(讨论)
|
||
|
||
1. 银行家算法基于"进程所需资源最大量"信息,**对充要性分析是不够的**(如上例保守性问题)。
|
||
2. 若能**预先给出进程完整资源命令序列**,则可给出死锁避免的**充要性算法**,但复杂度为 **NP 完全**。
|
||
3. 预先给出完整命令序列是**困难的**(程序有分支、循环)。
|
||
|
||
---
|
||
|
||
### 5.8 死锁的检测
|
||
|
||
#### 5.8.1 死锁检测的数据结构
|
||
|
||
| 数据结构 | 含义 |
|
||
|---------|------|
|
||
| Available | 系统可用资源 |
|
||
| Allocation | 已分配 |
|
||
| Request | 进程当前请求 |
|
||
| Work(临时) | 模拟可用资源 |
|
||
| Finish(临时) | 进程是否"完成" |
|
||
|
||
#### 5.8.2 死锁检测算法
|
||
|
||
```
|
||
1. Work := Available
|
||
若 Allocation[i] = 0,则 Finish[i] := true,否则 Finish[i] := false
|
||
2. 寻找 i 满足:
|
||
Finish[i] = false 且 Request[i] ≤ Work
|
||
若不存在,转 4。
|
||
3. Work := Work + Allocation[i]
|
||
Finish[i] := true
|
||
转 2。
|
||
4. 若 ∃i, Finish[i] = false → 死锁;
|
||
否则 → 无死锁。
|
||
```
|
||
|
||
**两个关键备注**:
|
||
- 算法可检测到**参与死锁的全部进程**,包括占有资源和不占有资源的进程。
|
||
- 若只想检测**占有资源**的进程(因为只有占资源的进程需要恢复),则初始化时改为:
|
||
**对所有 Allocation[i] = 0 的 i,置 Finish[i] = true**(认为空手的进程不会卡死别人)。
|
||
- 设 P 是所有进程集合,P' ⊆ P 是所有占有资源的进程集合,则 **P 死锁 ⟺ P' 死锁**。因此只检测 P' 可缩小检测范围、降低开销。
|
||
|
||
#### 5.8.3 死锁检测算法例题
|
||
|
||
> R = {A(7), B(3), C(6)},P = {p0, p1, p2, p3, p4}
|
||
>
|
||
> | 进程 | Allocation (A B C) | Request (A B C) | Available (A B C) |
|
||
> |------|--------------------|------------------|--------------------|
|
||
> | p0 | 0 1 0 | 0 0 0 | 0 1 0 |
|
||
> | p1 | 2 0 0 | 2 0 2 | |
|
||
> | p2 | 3 0 3 | 0 0 0 | |
|
||
> | p3 | 2 1 1 | 1 0 0 | |
|
||
> | p4 | 0 0 2 | 0 0 2 | |
|
||
|
||
**步骤**:
|
||
- Work = (0,1,0);Finish = (F,F,F,F,F)
|
||
- p0:Request(0,0,0) ≤ Work(0,1,0) ✓,Work := (0,1,0)+(0,1,0) = (0,2,0),Finish[p0]=T
|
||
- p2:Request(0,0,0) ≤ Work(0,2,0) ✓,Work := (0,2,0)+(3,0,3) = (3,2,3),Finish[p2]=T
|
||
- p1:Request(2,0,2) ≤ Work(3,2,3) ✓,Work := (3,2,3)+(2,0,0) = (5,2,3),Finish[p1]=T
|
||
- p3:Request(1,0,0) ≤ Work(5,2,3) ✓,Work := (5,2,3)+(2,1,1) = (7,3,4),Finish[p3]=T
|
||
- p4:Request(0,0,2) ≤ Work(7,3,4) ✓,Work := (7,3,4)+(0,0,2) = (7,3,6),Finish[p4]=T
|
||
|
||
**所有 Finish = true,未死锁**。
|
||
|
||
**若 p2 再请求 Request[2] = (0,0,1)**:
|
||
|
||
| 进程 | Allocation | Request |
|
||
|------|-----------|---------|
|
||
| p0 | 0 1 0 | 0 0 0 |
|
||
| p1 | 2 0 0 | 2 0 2 |
|
||
| p2 | 3 0 3 | 0 0 1 |
|
||
| p3 | 2 1 1 | 1 0 0 |
|
||
| p4 | 0 0 2 | 0 0 2 |
|
||
|
||
- Work = (0,1,0),找满足 Request ≤ Work 的进程:p0(Request 全 0)✓ → Work = (0,2,0)
|
||
- p2 Request(0,0,1) > Work(0,2,0) ✗;p1 ✗;p3 Request(1,0,0) > (0,2,0) ✗;p4 Request(0,0,2) > (0,2,0) ✗
|
||
- 算法终止,**p1, p2, p3, p4 的 Finish 仍为 false** → **死锁,参与死锁的进程集合 = {p1, p2, p3, p4}**。
|
||
|
||
#### 5.8.4 死锁检测的时机
|
||
|
||
| 检测时机 | 优点 | 缺点 |
|
||
|---------|------|------|
|
||
| **每次资源等待时检测** | 发现早,恢复代价小 | 开销大(频繁) |
|
||
| **定时检测**(如每小时) | 开销可控 | 死锁到恢复有延迟 |
|
||
| **CPU 利用率下降时检测** | 动态适应 | 阈值难调,可能漏检 |
|
||
|
||
---
|
||
|
||
### 5.9 死锁的恢复
|
||
|
||
检测到死锁后,必须打破循环。**三种恢复方法**:
|
||
|
||
1. **重新启动系统**:最简单,代价最大,会影响未参与死锁的进程。
|
||
2. **终止进程(Process Termination)**:
|
||
- 终止**环路上占有资源的进程**。
|
||
- (a) 一次性全部终止;(b) 逐步终止(按优先级、代价函数选择)。
|
||
3. **剥夺资源(Resource Preemption)+ 进程回退(Rollback)**:
|
||
- 选定受害者(victim)→ 剥夺其资源。
|
||
- 进程回退到某个安全状态(保存 snapshot)。
|
||
- **问题**:保存快照代价大;消除影响困难;**可能造成饥饿(starvation)**。
|
||
|
||
---
|
||
|
||
### 5.10 鸵鸟算法(Ostrich Algorithm)
|
||
|
||
**视而不见**——假装死锁不会发生。
|
||
|
||
- **支持方(工程师)**:死锁发生频率 < 其它故障引起系统瘫痪的频率;死锁处理开销 > 死锁危害。
|
||
- **反对方(数学家)**:必须处理,无论代价如何。
|
||
- **现实**:大多数实际操作系统(如 UNIX、Linux、Windows)采用鸵鸟算法。UNIX 进程数上限 50 多即由此考虑(避免复杂资源分配图)。
|
||
- **结论**:是工程权衡的产物,不是"好的"理论方案。
|
||
|
||
---
|
||
|
||
### 5.11 有关问题的讨论
|
||
|
||
1. **充要性算法**:已知进程资源活动序列即可给出充要性算法,但困难在于程序有分支与循环,复杂度为 **NP 完全**。
|
||
2. **生灭资源问题**:消耗性资源(如消息、信号)与可重用资源(如打印机、内存)并存时,死锁分析更复杂。
|
||
3. **两阶段封锁(2PL)**:数据库领域,增长阶段有可能死锁(仍需检测)。
|
||
|
||
---
|
||
|
||
### 5.12 饥饿与活锁(Starvation & Livelock)
|
||
|
||
#### 5.12.1 饥饿定义
|
||
|
||
**饥饿(Starvation)**:当等待时间给进程推进和响应带来明显影响时,称发生进程饥饿。饥饿到一定程度,进程即使完成也不再具有实际意义时,称该进程被**饿死(starved to death)**。
|
||
|
||
本质:**等待时间没有上界**(但不是"永远等不到")。
|
||
|
||
#### 5.12.2 饥饿与活锁的关系
|
||
|
||
- **排队等待**(如信号量 P 操作阻塞)→ 不会活锁。
|
||
- **忙式等待**(如自旋锁)→ 等待时间没上界 → 可能饿死。
|
||
- **忙式等待条件下发生的饥饿,称为活锁(LiveLock)**。
|
||
|
||
活锁:进程一直在运行("忙着"),但推进无效。如两进程在走廊相遇,互相礼让 → 反复让路 → 永远过不去。
|
||
|
||
#### 5.12.3 死锁与饥饿的对比(必考对比表)
|
||
|
||
| 维度 | 死锁(Deadlock) | 饥饿/饿死(Starvation) |
|
||
|------|-----------------|------------------------|
|
||
| 等待状态 | 一定处于等待 | 死锁进程等待,饿死可能忙等(活锁) |
|
||
| 等待资源 | **永远得不到** | 资源可能被释放,但**不会分给自己**,等待无上界 |
|
||
| 循环等待 | **一定有循环等待** | **不一定**有循环 |
|
||
| 涉及进程数 | **至少 2 个** | **可能只有 1 个** |
|
||
| 检测 | 资源分配图化简 | 通常依赖公平调度策略(FIFO、优先级老化等) |
|
||
| 解决方案 | 预防/避免/检测+恢复 | 公平调度、优先级老化(Aging) |
|
||
|
||
---
|
||
|
||
### 5.13 死锁的例子——过河问题(Bridge Crossing)
|
||
|
||
**问题描述**:一座独木桥,两岸有人要过河。桥同一方向可并行,反方向不行。
|
||
|
||
**死锁可能**:东、西两个方向各有 1 人上桥,双方互相等待对方先下桥。
|
||
|
||
**预防方案**:同一时刻只允许一个方向通行(互斥)。
|
||
- 用信号量 `mutex` 保护计数器 `east_crossing`、`west_crossing`、`east_wait`、`west_wait`、`wq`、`eq`。
|
||
- 西面过河者:若 `east_crossing > 0`,则排队到 `wq`;否则上桥 `west_crossing++`;过河完后唤醒东面等待者。
|
||
|
||
**课后思考**:给出"无饿死"的解法(提示:用 FIFO 队列严格排队,避免某方向一直插队)。
|
||
|
||
#### 第二个过河问题(带路径约束)
|
||
|
||
桥上有 8 段(1-2-3-4-...),W→E 与 E→W 各走特定路径:
|
||
- W→E:1→2→3→4→5→6→...(P(s1)→P(s2)→...)
|
||
- E→W:5→6→7→8→1→2→...(P(s5)→P(s6)→...)
|
||
- 全局信号量 S 初值 5,s1..s8 初值 1。
|
||
- 要求:(1) 无死锁;(2) 无饿死;(3) 并行度高。
|
||
|
||
通过在每段设置信号量并按路径顺序 P、V,并控制对向并发数 ≤ 5,实现解。
|
||
|
||
---
|
||
|
||
### 5.14 简单组合资源死锁的静态分析
|
||
|
||
**已知**:每个进程关于资源的活动序列(申请、释放顺序)。
|
||
**判断**:有无死锁可能性。
|
||
|
||
**步骤**:
|
||
1. 以每个进程"占有资源、申请资源"作为一个**状态**,记作:`(pi : aj : ak1, ..., akn) = (进程 : 请求 : 占有)`。
|
||
2. 以每个状态为一个**节点**。
|
||
3. 若 s1 所申请资源为 s2 所占有,则由 s1 向 s2 画有向弧(**相同进程之间不画**)。
|
||
4. 找出所有环路。
|
||
5. 判断环路上状态是否能**同时到达**:
|
||
- 环路中有**相同进程** → 不能到达 → 无死锁。
|
||
- 环路中有**相同被占有资源** → 不能到达 → 无死锁。
|
||
|
||
**典型例题**:R = {A, B, C, D, E, F, G},三进程:
|
||
```
|
||
p1: c d c a b d a b
|
||
p2: d e d b f e b f
|
||
p3: c e e f a e f a
|
||
```
|
||
画出状态图,找到环路后用反证法证明某条环路不可达(线1不可达,反证线1可达则线2可达,又推出矛盾)。
|
||
|
||
---
|
||
|
||
### 5.15 同种组合资源死锁的必要条件
|
||
|
||
**条件**:只有一种资源类,但数量有限。
|
||
|
||
设:
|
||
- **M**:该类资源的总数量
|
||
- **N**:使用该类资源的进程数量
|
||
- **Σ**:所有进程所需该类资源的总量(每个进程一个最大需求)
|
||
|
||
**定理**:当 **Σ < M + N** 时,一定没有死锁;当 **Σ ≥ M + N** 时,至少存在某种交叉有死锁可能。
|
||
|
||
**证明思路**:假设死锁,n 个进程参与了死锁(2 ≤ n ≤ N)。
|
||
- 参与死锁的进程所需资源总量 ≥ M + n(因为死锁状态下,所有 M 个资源都被持有,且至少多 1 个被循环等待)。
|
||
- 未参与死锁的进程所需资源总量 ≥ N − n(每个未参与的进程至少需要 1 个,因已假设都"可能等")。
|
||
- 故 Σ ≥ M + n + (N − n) = M + N。
|
||
|
||
**例题**:
|
||
- 例 1:M=15, N=4, P1(4)+P2(6)+P3(1)+P4(7) = 18 < M+N = 19 → **无死锁可能**。
|
||
- 例 2:M=15, N=4, P1(5)+P2(6)+P3(1)+P4(7) = 19 ≥ M+N = 19 → **有死锁可能**。
|
||
- 一种死锁情形:P1 占 5、P2 占 5、P3 占 1、P4 占 4,总共 15 个,全部分光且仍在循环等待。
|
||
|
||
---
|
||
|
||
## 二、考点总结
|
||
|
||
### 考点 1:死锁的定义与四个必要条件(Coffman 条件)
|
||
|
||
- **内容**:
|
||
1. 互斥使用(Mutual Exclusion)
|
||
2. 不可抢占(Non-preemption)
|
||
3. 保持申请(Hold-and-Wait)
|
||
4. 循环等待(Circular Wait)
|
||
- 四条件**同时满足**才可能死锁(必要条件);每类资源单实例时为**充要条件**。
|
||
- 破坏任一条件即可预防死锁。
|
||
- **考查方式**:选择、填空、简答。
|
||
- **可能的题目**:
|
||
1. 死锁的四个必要条件是什么?它们之间是什么关系?
|
||
**答**:见上"内容";4 个条件同时成立是死锁的**必要条件**;每类资源仅一个实例时是**充要条件**。
|
||
2. (选择)破坏哪个条件能预防死锁?
|
||
A. 互斥 B. 不可抢占 C. 保持申请 D. 以上均可
|
||
**答**:D(破坏任一条件均可消除死锁)。
|
||
|
||
---
|
||
|
||
### 考点 2:死锁与饥饿的对比
|
||
|
||
- **内容**:见 5.12.3 对比表,特别强调:
|
||
- 死锁:等待永远得不到的资源;一定有循环等待;至少 2 个进程。
|
||
- 饥饿:等待可能释放但分不到自己的资源,等待无上界;可能没有循环;可能只涉及 1 个进程。
|
||
- **考查方式**:选择、填空、简答。
|
||
- **可能的题目**:
|
||
1. (选择)下列关于死锁与饥饿的说法错误的是?
|
||
A. 死锁一定涉及循环等待
|
||
B. 饥饿可能只涉及一个进程
|
||
C. 死锁进程一定处于等待状态
|
||
D. 饥饿进程的等待时间一定有上界
|
||
**答**:D(饥饿的关键是"无上界")。
|
||
2. 简述活锁与死锁的区别。
|
||
**答**:活锁是忙式等待条件下的饥饿,进程"忙着"但无进展;死锁是等待永远不会释放的资源。活锁可在运行,死锁必阻塞。
|
||
|
||
---
|
||
|
||
### 考点 3:死锁处理的四种策略及鸵鸟算法
|
||
|
||
- **内容**:预防(静态)、避免(动态,银行家算法)、检测+恢复、鸵鸟算法(忽略)。
|
||
- **考查方式**:选择、填空、简答。
|
||
- **可能的题目**:
|
||
1. (简答)死锁预防、避免、检测三种策略的优缺点对比。
|
||
**答**:
|
||
- 预防:静态,破坏必要条件,资源利用率低。
|
||
- 避免:动态,运行时检查安全性(如银行家算法),需预知最大需求。
|
||
- 检测+恢复:允许死锁,定期检测,再终止或剥夺,开销低但恢复有代价。
|
||
2. (选择)UNIX 采用哪种死锁处理策略?
|
||
**答**:鸵鸟算法(Ostrich)。
|
||
|
||
---
|
||
|
||
### 考点 4:资源分配图与化简
|
||
|
||
- **内容**:申请边、分配边、约简算法、死锁定理。
|
||
- **考查方式**:选择、填空、综合题(画图+判定)。
|
||
- **可能的题目**:
|
||
1. (画图+判定)给定进程资源关系,画资源分配图,并判断是否死锁。
|
||
**答**:按规则:申请边从进程指向资源类(虚线),分配边从资源实例指向进程(实线)。化简时反复找"无请求边"的进程,删除其所有分配边。若最终全孤立 → 安全;否则死锁。
|
||
2. (选择)有环路的资源分配图是否一定死锁?
|
||
**答**:不一定;只有每类资源仅一个实例时,有环才等价于死锁。多实例时可能通过环外资源打破死锁。
|
||
|
||
---
|
||
|
||
### 考点 5:死锁预防——预先分配法与有序分配法
|
||
|
||
- **内容**:
|
||
- 预先分配法:一次性申请全部资源 → 破坏"保持申请"。
|
||
- 有序分配法:按资源编号递增申请 → 破坏"循环等待"。
|
||
- **考查方式**:选择、填空、简答。
|
||
- **可能的题目**:
|
||
1. (选择)有序分配法破坏 Coffman 条件的哪个?
|
||
**答**:循环等待。
|
||
2. (简答)有序分配法为何能防止死锁?(反证法说明)
|
||
**答**:假设死锁,存在环路 p1→p2→...→pn→p1,按有序申请规则有 F(rk1) < F(rk2) < ... < F(rkn) < F(rk1),矛盾。
|
||
|
||
---
|
||
|
||
### 考点 6:银行家算法的数据结构
|
||
|
||
- **内容**:Available、Claim/Max、Allocation、Need、Request;以及临时变量 Work、Finish。
|
||
- **考查方式**:填空、简答。
|
||
- **可能的题目**:
|
||
1. (填空)Need[i] = __________ − Allocation[i]。
|
||
**答**:Claim[i](或 Max[i])。
|
||
2. (简答)银行家算法的 5 个数据结构和 2 个临时变量名称及含义。
|
||
**答**:见 5.7.3 表格。
|
||
|
||
---
|
||
|
||
### 考点 7:银行家算法——资源分配主流程(必考大题)
|
||
|
||
- **内容**:
|
||
1. Request ≤ Need?
|
||
2. Request ≤ Available?
|
||
3. 试探分配。
|
||
4. 安全性检查 → 安全则真正分配;不安全则撤销试探,进程等待。
|
||
- **考查方式**:计算大题。
|
||
- **可能的题目**(计算):
|
||
1. 系统有 5 个进程 P0..P4,3 类资源 A(10)、B(5)、C(7),初始快照如下。P2 请求 (1,0,2),P4 请求 (3,3,0),P0 请求 (0,2,0),分别判断能否分配。
|
||
|
||
> | 进程 | Max (A B C) | Allocation (A B C) | Need (A B C) | Available (A B C) |
|
||
> |------|-------------|--------------------|---------------|--------------------|
|
||
> | P0 | 7 5 3 | 0 1 1 | 7 4 2 | 3 3 3 |
|
||
> | P1 | 3 2 2 | 2 0 0 | 1 2 2 | |
|
||
> | P2 | 9 0 2 | 3 0 0 | 6 0 2 | |
|
||
> | P3 | 2 2 2 | 2 1 1 | 0 1 1 | |
|
||
> | P4 | 4 3 3 | 0 0 2 | 4 3 1 | |
|
||
|
||
**解答**:
|
||
|
||
(a) **P2 请求 (1,0,2)**:
|
||
- Request(1,0,2) ≤ Need(6,0,2) ✓
|
||
- Request(1,0,2) ≤ Available(3,3,3) ✓
|
||
- 试探分配后 Available=(2,3,1), Allocation[P2]=(4,0,2), Need[P2]=(5,0,0)
|
||
- 安全性检查:⟨P3, P1, P4, P2, P0⟩ 是安全序列 → **安全,真正分配**。
|
||
|
||
(b) **P4 请求 (3,3,0)**:
|
||
- Request(3,3,0) > Available(2,3,1) → **不满足,P4 等待**。
|
||
|
||
(c) **P0 请求 (0,2,0)**(此时 Available 已是 (2,3,1)):
|
||
- Request(0,2,0) ≤ Need(7,4,3) ✓
|
||
- Request(0,2,0) ≤ Available(2,3,1) ✓
|
||
- 试探分配后 Available=(2,1,1), Allocation[P0]=(0,3,0), Need[P0]=(7,2,3)
|
||
- 安全性检查:无可满足进程(P1 需 (1,2,2) > (2,1,1) 等) → **不安全,撤销分配,P0 等待**。
|
||
|
||
---
|
||
|
||
### 考点 8:安全性算法(必考大题)
|
||
|
||
- **内容**:见 5.7.5,五个步骤。
|
||
- **考查方式**:计算大题(每年必考)。
|
||
- **可能的题目**:见考点 7。
|
||
|
||
---
|
||
|
||
### 考点 9:银行家算法的保守性
|
||
|
||
- **内容**:基于"最大需求"判断是**充分不必要**的,可能拒绝本可分配的资源。
|
||
- **考查方式**:选择、简答。
|
||
- **可能的题目**:
|
||
1. (简答)简述银行家算法的局限性。
|
||
**答**:(1) 要求进程预知最大需求,实际困难;(2) 进程数量与资源类别增加时代价大;(3) 基于最大需求判断,对实际安全序列可能"误判不安全",具有保守性;(4) 程序有分支循环,无法预知完整序列,精确算法为 NP 完全。
|
||
|
||
---
|
||
|
||
### 考点 10:死锁检测算法
|
||
|
||
- **内容**:与银行家算法的安全性算法类似,但用 Request 替代 Need。
|
||
- **考查方式**:计算大题。
|
||
- **可能的题目**:
|
||
|
||
> 系统 R = {A(7), B(3), C(6)},P = {p0, p1, p2, p3, p4}。当前快照:
|
||
>
|
||
> | 进程 | Allocation (A B C) | Request (A B C) | Available (A B C) |
|
||
> |------|--------------------|------------------|--------------------|
|
||
> | p0 | 0 1 0 | 0 0 0 | 0 1 0 |
|
||
> | p1 | 2 0 0 | 2 0 2 | |
|
||
> | p2 | 3 0 3 | 0 0 0 | |
|
||
> | p3 | 2 1 1 | 1 0 0 | |
|
||
> | p4 | 0 0 2 | 0 0 2 | |
|
||
>
|
||
> 此时 p2 又请求 (0,0,1),请用死锁检测算法判断系统是否死锁,并列出参与死锁的进程。
|
||
|
||
**解答**:
|
||
- 新 Request 矩阵:p2 改为 (0,0,1)。
|
||
- Work = (0,1,0),Finish 初始化:p0 Allocation≠0 → F;p2 Allocation≠0 → F;p1, p3, p4 同理 F。
|
||
- 选 p0:Request(0,0,0) ≤ (0,1,0) ✓ → Work = (0,1,0)+(0,1,0) = (0,2,0),Finish[p0]=T
|
||
- 检查剩余:p1 需 (2,0,2) > (0,2,0) ✗;p2 需 (0,0,1) > (0,2,0) ✗;p3 需 (1,0,0) > (0,2,0) ✗;p4 需 (0,0,2) > (0,2,0) ✗
|
||
- **算法终止,p1, p2, p3, p4 的 Finish 仍为 false → 系统死锁,参与死锁进程集合 = {p1, p2, p3, p4}**。
|
||
|
||
---
|
||
|
||
### 考点 11:死锁检测时机与恢复方法
|
||
|
||
- **内容**:三种检测时机(等待时、定时、CPU 利用率下降);三种恢复方法(重启、终止、剥夺)。
|
||
- **考查方式**:选择、填空、简答。
|
||
- **可能的题目**:
|
||
1. (选择)死锁恢复的代价从小到大排列?
|
||
**答**:剥夺部分资源 < 终止部分进程 < 重启系统。
|
||
2. (填空)剥夺资源 + 进程回退方案的最大问题是 ________ 和 ________。
|
||
**答**:保存 snapshot 代价大;可能造成 starvation(饥饿)。
|
||
|
||
---
|
||
|
||
### 考点 12:鸵鸟算法(Ostrich Algorithm)
|
||
|
||
- **内容**:忽略死锁,工程权衡,实际系统常用。
|
||
- **考查方式**:选择、简答。
|
||
- **可能的题目**:
|
||
1. (选择)UNIX、Linux、Windows 采用哪种死锁处理策略?
|
||
**答**:鸵鸟算法。
|
||
2. (简答)为何实际系统多用鸵鸟算法?
|
||
**答**:死锁发生频率极低,处理开销(检测+恢复)反而更大;从工程角度"忽略"是最优选择。
|
||
|
||
---
|
||
|
||
### 考点 13:组合资源死锁的静态分析
|
||
|
||
- **内容**:画状态转移图、找环路、判断环路是否可达(相同进程或相同占有资源 → 不可达)。
|
||
- **考查方式**:综合题。
|
||
- **可能的题目**:
|
||
|
||
> R = {A,B,C,D,E,F,G},三进程活动序列如下。判断有无死锁可能。
|
||
> ```
|
||
> p1: c d c a b d a b
|
||
> p2: d e d b f e b f
|
||
> p3: c e e f a e f a
|
||
> ```
|
||
|
||
**思路**:以"进程:请求:占有"为节点画有向图,找环路 → 用反证法证明环路不可达(线1不可达;反设线1可达,则线2可达,进而 p2 先于 p1、p3 先于 p2、p1 先于 p3,矛盾)。**结论:无死锁可能性**。
|
||
|
||
---
|
||
|
||
### 考点 14:同种资源死锁的充要条件(Σ vs M+N)
|
||
|
||
- **内容**:M 资源数、N 进程数、Σ 总需求。
|
||
- Σ < M + N → 一定无死锁。
|
||
- Σ ≥ M + N → 至少存在某种交叉有死锁可能。
|
||
- **考查方式**:计算题、判断题。
|
||
- **可能的题目**:
|
||
1. M=6, N=3, P1(3)+P2(2)+P3(4)=9, 是否可能死锁?
|
||
**答**:M+N = 9, Σ = 9 ≥ 9 → **可能死锁**(存在如 P1 占 3、P2 占 2、P3 占 1 并循环等待等死锁情形)。
|
||
2. M=6, N=3, P1(2)+P2(2)+P3(3)=7 < 9 → **一定无死锁**。
|
||
|
||
---
|
||
|
||
### 考点 15:死锁类型(同种/异种资源、通讯死锁、活锁)
|
||
|
||
- **内容**:
|
||
- 不同类资源死锁(最常见):两进程互持对方所需资源。
|
||
- 同类资源死锁:资源数不够用且请求总和超量。
|
||
- 通讯死锁:进程互等消息。
|
||
- 活锁:"After you / After you",忙等无进展。
|
||
- **考查方式**:选择、填空。
|
||
- **可能的题目**:
|
||
1. (选择)4 台打印机,P1 申请 8 次、P2 申请 4 次,是否会死锁?
|
||
**答**:当 P1 占 3、P2 占 1 时,P1 还需 5、P2 还需 3,总需 8 > 4,**可死锁**。
|
||
|
||
---
|
||
|
||
### 考点 16:过河问题(综合应用题)
|
||
|
||
- **内容**:使用信号量 `mutex` + `wq`/`eq` 实现"同方向可并发,反方向必须互斥"。要求:无死锁、无饿死、并行度高。
|
||
- **考查方式**:综合应用题(写出信号量初值、P/V 操作)。
|
||
- **可能的题目**:
|
||
1. 写出"无死锁、无饿死"的过河问题完整解法(含信号量定义和 P/V 序列)。
|
||
**答要点**:
|
||
- 全局信号量 `S`(限制总桥上人数)、分段信号量 `s1..s8`(控制每段互斥)。
|
||
- 西→东:`P(S); P(s1); …; P(s4); 走过; V(s4); …; V(s1); V(S);`
|
||
- 东→西:`P(S); P(s5); …; P(s8); 走过; V(s8); …; V(s5); V(S);`
|
||
- 通过 FIFO 队列与计数变量保证无饿死(见 PPT 5.13 的代码)。
|
||
|
||
---
|
||
|
||
### 考点 17:死锁定理(资源分配图约简)
|
||
|
||
- **内容**:S 是死锁状态 ⟺ 资源分配图不可完全约简。
|
||
- **考查方式**:选择、简答。
|
||
- **可能的题目**:
|
||
1. (简答)叙述死锁定理及其证明思路。
|
||
**答**:资源分配图可完全约简 ⟺ 无死锁。证明思路:若可完全约简,可按约简顺序找到安全序列;反之若无死锁,必有进程可推进并最终释放资源,对应化简步骤,故可完全约简。逆否:不可完全约简 → 死锁。
|
||
|
||
---
|
||
|
||
### 考点 18:饥饿的解决方案
|
||
|
||
- **内容**:公平调度、优先级老化(Aging)、FIFO 队列。
|
||
- **考查方式**:简答。
|
||
- **可能的题目**:
|
||
1. (简答)饥饿有哪些常见解决方案?
|
||
**答**:
|
||
- 公平调度(FIFO、先来先服务)。
|
||
- 优先级老化(等待越久优先级越高)。
|
||
- 多队列反馈调度。
|
||
- 避免选同一进程作为剥夺受害者(防饥饿)。
|
||
|
||
---
|
||
|
||
### 考点 19:死锁检测的初始化差异(重要细节)
|
||
|
||
- **内容**:两种初始化方式:
|
||
- 默认:所有 Finish=false,按 Request ≤ Work 找。
|
||
- 改进:对 Allocation[i]=0 的进程直接 Finish[i]=true(空手的进程不会卡别人)。
|
||
- 后者只检测占有资源的进程 P',不影响结论(P 死锁 ⟺ P' 死锁)。
|
||
- **考查方式**:选择、填空。
|
||
- **可能的题目**:
|
||
1. (填空)死锁检测算法中,为减少开销,对 Allocation[i]=0 的进程应设 Finish[i] = ________。
|
||
**答**:true。
|
||
|
||
---
|
||
|
||
### 考点 20:死锁 vs 活锁 vs 饥饿(三概念辨析)
|
||
|
||
- **内容**:
|
||
- **死锁**:阻塞等待 + 永远得不到。
|
||
- **活锁**:忙式等待 + 看似在跑但实际无进展(如两进程互相让路)。
|
||
- **饥饿**:等待时间无上界但未必死锁(资源可能被释放但分不到)。
|
||
- **考查方式**:选择、填空、简答。
|
||
- **可能的题目**:
|
||
1. (选择)两进程在独木桥两端互相礼让、谁也过不去,属于?
|
||
A. 死锁 B. 活锁 C. 饥饿 D. 正常调度
|
||
**答**:B(活锁)。
|
||
2. (简答)举例说明死锁、活锁、饥饿的典型场景。
|
||
**答**:
|
||
- 死锁:A 占 R1 等 R2,B 占 R2 等 R1。
|
||
- 活锁:两进程在走廊相遇互相让路,重复让路→永远过不去。
|
||
- 饥饿:低优先级进程长期得不到 CPU(虽然 CPU 空闲着)。
|
||
|
||
---
|
||
|
||
**本章复习建议**:
|
||
1. **必背**:Coffman 4 条件、银行家算法的 5 数据结构 + 2 临时变量、安全性算法流程、死锁定理。
|
||
2. **必练**:每年至少做 3 道银行家算法计算题(含初始安全性检查 + 多个请求处理)。
|
||
3. **必理解**:资源分配图化简、死锁检测算法(与安全性算法对比)。
|
||
4. **必对比**:死锁 vs 饥饿 vs 活锁;预防 vs 避免 vs 检测 vs 恢复。
|
||
5. **必记**:Σ < M+N → 一定无死锁;Σ ≥ M+N → 可能死锁。
|