- 死锁的产生原因
- 竞争资源:当多个进程共享系统资源(如内存、I/O设备、文件等),而资源数量不足以满足所有进程的需求时,进程之间会因争夺资源而陷入等待状态。
- 进程推进顺序非法:如果进程在运行过程中请求和释放资源的顺序设计不合理,例如先持有部分资源再请求其他资源却长期得不到响应,就可能导致死锁。
- 死锁的4个必要条件(必须同时满足才会发生死锁)
- 互斥条件:资源不能被多个进程共享使用,某一时刻只能由一个进程独占。
- 请求与保持条件(Hold and Wait):进程已经保持了至少一个资源,但仍请求其他被占用的资源。
- 不可剥夺条件(No Preemption):已分配给进程的资源,在未使用完之前不能被系统强行回收或剥夺。
- 环路等待条件(Circular Wait):存在一个进程链,每个进程都在等待下一个进程所持有的资源,形成闭合的环路。
- 死锁的处理策略
- 鸵鸟策略:对死锁视而不见,认为其发生的概率极低,不采取任何措施(常见于桌面操作系统或嵌入式系统)。
- 预防策略:通过破坏上述四个必要条件之一来防止死锁发生:
- 破坏“请求保持”:采用静态分配法,要求进程在运行前一次性申请全部所需资源;
- 破坏“不可剥夺”:允许系统在必要时强制回收资源;
- 破坏“互斥”:尽量将资源改为可共享方式(但某些资源无法共享,如打印机);
- 破坏“环路等待”:规定资源按线性顺序申请,避免循环依赖。
- 避免策略:在资源动态分配过程中,判断此次分配是否会导致系统进入不安全状态,如银行家算法就是典型的死锁避免方法。
- 检测与解除策略:
- 使用资源分配图定期检测是否存在环路;
- 若检测到死锁,则通过终止进程或抢占资源的方式解除死锁。
补充说明:
进程资源有向图是分析死锁的重要工具:
- 方框表示资源类,圆圈表示进程;
- 箭头
进程 → 资源表示该进程正在请求该资源; - 箭头
资源 → 进程表示该资源已分配给该进程; - 当图中出现环路时,说明可能存在死锁(对于单类资源,环路即意味着死锁;多类资源需进一步分析)。
银行家算法是一种死锁避免算法,用于在动态分配资源时判断系统是否处于安全状态,即是否存在一个进程执行序列,使得所有进程都能顺利完成。其核心思想是:在为进程分配资源前,先模拟分配,检查系统是否仍处于安全状态,若安全才真正分配。
一、基本数据结构
设系统中有n个进程,m种资源类型:
- Available[1…m]:当前可用的每种资源数量。
- Max[n][m]:每个进程对各类资源的最大需求量。
- Allocation[n][m]:每个进程当前已分配到的各类资源数。
- Need[n][m] = Max - Allocation:每个进程还需要的资源数。
二、安全性检查算法(Safety Algorithm)
步骤如下:
初始化:
Work[1..m] = Available(工作向量,表示当前可分配资源)Finish[i] = false(标记进程是否成功完成)
寻找满足条件的进程:
- 找到一个进程
i,使得:Finish[i] == falseNeed[i] ≤ Work(该进程所需资源不超过当前可用资源)
- 找到一个进程
若找到这样的进程:
- 假设它能获得所需资源并运行完毕,则释放其占用资源:
Work = Work + Allocation[i]Finish[i] = true
- 回到第2步继续查找
- 假设它能获得所需资源并运行完毕,则释放其占用资源:
若所有进程都满足
Finish[i] == true,则系统处于安全状态;否则为不安全状态。
✅ 安全序列:按
Finish成功顺序排列的进程序列称为安全序列。只要存在至少一个安全序列,系统就是安全的。
三、资源请求处理流程
当某个进程提出资源请求时:
检查请求是否超过其声明的最大需求:
- 若
Request[i] > Need[i]→ 出错(非法请求)
- 若
检查系统是否有足够资源:
- 若
Request[i] > Available→ 进程等待
- 若
试探性分配:
- 更新状态:
Available = Available - Request[i] Allocation[i] = Allocation[i] + Request[i] Need[i] = Need[i] - Request[i]
- 更新状态:
调用安全性检查算法判断新状态是否安全。
若安全 → 真正分配;
否则 → 撤销试探性分配,让进程等待。
四、举例说明
假设有3个进程 P0、P1、P2,2种资源 A 和 B,总量为 (10, 7):
| Max | Allocation | Need | |
|---|---|---|---|
| P0 | (7,5) | (0,1) | (7,4) |
| P1 | (3,2) | (2,0) | (1,2) |
| P2 | (9,5) | (3,3) | (6,2) |
Available = (3,3)
执行安全性检查:
可行?P1: Need=(1,2) ≤ (3,3) → 是
→ Work += Allocation[P1] = (3,3)+(2,0)=(5,3),Finish[P1]=trueP2: Need=(6,2) ≤ (5,3)? 否 → 跳过
P0: Need=(7,4) ≤ (5,3)? 否
→ 卡住,无法完成所有进程 →无安全序列?
但再试其他顺序或重新计算可能发现某些情况仍可解。
实际中需遍历所有未完成进程寻找可行路径。
✅ 结论:只有当“试探性分配”后仍能找到一个安全序列时,才允许资源分配。