银行家算法技术总结
·
银行家算法技术总结与性能优化方案
一、算法基础概述
1.1 核心定义
银行家算法 是操作系统中经典的死锁避免算法,通过资源请求前置校验、安全状态模拟推演,提前拒绝会导致系统进入不安全状态的资源分配,从源头规避死锁。
1.2 核心数据结构
- Available:一维数组,记录系统当前空闲可用资源
- Max:二维矩阵,记录每个进程的最大资源需求
- Allocation:二维矩阵,记录每个进程已分配资源
- Need:二维矩阵,记录进程剩余资源需求,计算公式:Need=Max−AllocationNeed = Max - AllocationNeed=Max−Allocation
- Work:临时资源数组,安全检测中模拟系统空闲资源
- Finish:标记数组,标识进程是否可正常执行完成
1.3 执行流程
- 校验进程本次资源请求 RequestRequestRequest 是否大于自身 NeedNeedNeed,超出则直接拒绝
- 校验 RequestRequestRequest 是否大于系统当前 AvailableAvailableAvailable,资源不足则进程等待
- 执行试探性资源分配,临时更新各类资源数据
- 运行安全状态检测,判断是否存在合法安全序列
- 安全则正式分配资源,不安全则撤销分配并拒绝请求
1.4 银行家算法执行步骤
步骤1:进程发出资源请求
进程 PiP_iPi 向系统发起资源请求,请求向量记为 RequestiRequest_iRequesti。
步骤2:合法性检查(请求预校验)
对本次请求做两次基础校验,任何一项不满足都不进入后续流程:
- 检查是否超过自身最大需求:
Requesti≤NeediRequest_i \le Need_iRequesti≤Needi
不满足:说明请求资源超过进程的最大需求,判定为非法请求,直接拒绝。 - 检查系统当前可用资源是否足够:
Requesti≤AvailableRequest_i \le AvailableRequesti≤Available
不满足:当前空闲资源不足,进程需要等待。
步骤3:试探分配资源(假设分配)
如果上述两项检查都通过,系统临时修改资源数据,模拟分配资源,不做实际分配:
Available=Available−RequestiAvailable = Available - Request_iAvailable=Available−Requesti
Allocationi=Allocationi+RequestiAllocation_i = Allocation_i + Request_iAllocationi=Allocationi+Requesti
Needi=Needi−RequestiNeed_i = Need_i - Request_iNeedi=Needi−Requesti
步骤4:安全状态检测
系统需要判断:经过试探分配后,系统是否仍然处于安全状态,即是否存在安全序列:
- 初始化:
- Work=AvailableWork = AvailableWork=Available(将当前可用资源赋值给临时变量)
- 初始化
Finish数组,所有元素设为false(标记进程是否可执行完成)
- 循环查找可执行进程:
遍历所有进程,寻找满足以下两个条件的进程 (P_j):- Finish[j]=falseFinish[j] = falseFinish[j]=false(进程尚未标记为可完成)
- Needj≤WorkNeed_j \le WorkNeedj≤Work(进程的剩余需求 ≤ 当前可用资源)
- 模拟进程执行并释放资源:
找到满足条件的进程后,模拟其执行完成并释放所有资源:
Work=Work+AllocationjWork = Work + Allocation_jWork=Work+Allocationj
同时标记 Finish[j]=trueFinish[j] = trueFinish[j]=true。 - 判断结果:
- 若遍历结束后,所有
Finish元素均为true:存在安全序列,系统安全 → 正式分配资源。 - 若存在
false:系统不安全 → 撤销试探分配,进程等待。
- 若遍历结束后,所有
二、算法优缺点分析
2.1 优点
- 主动规避死锁,无需事后检测与解除,系统稳定性强
- 支持资源动态分配,相比静态一次性分配,资源利用率更高
- 逻辑规则标准化,易于理解、教学与小型场景落地
2.2 缺点
- 前置条件严苛,必须提前精准预估所有进程的最大资源需求,通用场景难以实现
- 算法假设进程连续执行、进程与资源数量固定,与真实动态运行场景不符
- 每次资源请求都需全量遍历检测,进程与资源规模变大后,计算性能开销显著提升
- 为保障系统安全,部分合法资源请求也会被拒绝,易造成进程长时间阻塞等待
- 无法应对进程异常退出、资源故障等突发运行场景
三、核心性能瓶颈
- 安全检测阶段全量遍历所有进程,时间复杂度高
- 试探分配时频繁深拷贝资源矩阵,内存与数据拷贝开销大
- 安全序列采用暴力检索,无剪枝逻辑,检索效率低
- 资源变动时执行全量重检测,检测粒度粗、冗余计算多
四、性能优化方案
4.1 安全检测逻辑优化
- 进程候选集剪枝:仅将满足 Need≤WorkNeed \le WorkNeed≤Work 的进程纳入遍历范围,减少循环次数
- 贪心排序检索:优先选择剩余资源需求最小的进程推演,加快安全序列查找
- 历史序列缓存:资源状态无大幅变动时,复用历史有效安全序列
- 增量检测机制:仅对发起请求及受影响的进程做局部校验,替代全局全量检测
4.2 数据结构与内存优化
- 原地回滚替代深拷贝:试探分配直接修改原数据,检测失败后通过加减法回滚数据,消除拷贝开销
- 向量向量化运算:使用批量向量对比替代多层循环,提升资源校验速度
- 数据分层存储:静态数据与动态数据分离存储,提升CPU缓存命中率
4.3 调度策略优化
- 合并资源请求:将进程多次小额请求合并为单次请求,减少安全检测触发次数
- 分级检测机制:设置快速预校验+分级检测,低风险请求简化检测逻辑
- 异步后台检测:临时分配资源,后台异步执行安全校验,异常时再回收资源(适用于可容忍低死锁风险场景)
4.4 业务与运行适配优化
- 动态修正最大需求:根据进程历史运行数据,动态更新 MaxMaxMax 数值,适配真实业务
- 进程资源分组管理:按业务划分进程与资源组,组内独立执行算法,支持并行检测
- 定时清理无效进程:及时销毁已结束进程,缩减遍历范围
五、配套死锁处理方案
5.1 主流死锁处理方式对比
- 死锁预防:破坏死锁四大必要条件,实现简单,资源利用率低
- 死锁避免(银行家算法):事前预判规避死锁,适用于封闭小型系统
- 死锁检测+解除:允许进入死锁状态,事后发现并修复,通用系统主流方案
5.2 死锁检测算法
沿用资源矩阵模型,遍历模拟进程执行,最终无法完成的进程集合即为死锁进程。
5.3 死锁解除策略
- 资源剥夺:强行回收死锁进程资源,分配至其他进程,业务影响最小
- 进程回滚:基于检查点将进程回退至正常状态,适用于事务型系统
- 终止进程:结束死锁进程并回收资源,实现最简单,存在任务丢失风险
- 系统重启:兜底方案,极端死锁场景下使用
六、代码实现示例
6.1 银行家算法完整代码
import copy
def is_safe(available, max_need, allocation, need):
n = len(need)
m = len(available)
work = copy.deepcopy(available)
finish = [False] * n
safe_seq = []
while len(safe_seq) < n:
found = False
for i in range(n):
if not finish[i]:
flag = True
for j in range(m):
if need[i][j] > work[j]:
flag = False
break
if flag:
for j in range(m):
work[j] += allocation[i][j]
finish[i] = True
safe_seq.append(f"P{i}")
found = True
if not found:
return False, []
return True, safe_seq
def bank_request(process_id, request, available, max_need, allocation, need):
n = len(need)
m = len(available)
for j in range(m):
if request[j] > need[process_id][j]:
print(f"进程P{process_id} 请求超出最大需求,拒绝分配")
return available, max_need, allocation, need
for j in range(m):
if request[j] > available[j]:
print(f"系统资源不足,进程P{process_id} 等待")
return available, max_need, allocation, need
temp_available = copy.deepcopy(available)
temp_allocation = copy.deepcopy(allocation)
temp_need = copy.deepcopy(need)
for j in range(m):
temp_available[j] -= request[j]
temp_allocation[process_id][j] += request[j]
temp_need[process_id][j] -= request[j]
safe, seq = is_safe(temp_available, max_need, temp_allocation, temp_need)
if safe:
print(f"分配成功,安全序列:{seq}")
return temp_available, max_need, temp_allocation, temp_need
else:
print("分配后系统不安全,拒绝请求")
return available, max_need, allocation, need
if __name__ == "__main__":
Available = [3, 3, 2]
Max = [[7, 5, 3],[3, 2, 2],[9, 0, 2],[2, 2, 2],[4, 3, 3]]
Allocation = [[0, 1, 0],[2, 0, 0],[3, 0, 2],[2, 1, 1],[0, 0, 2]]
Need = []
for i in range(len(Max)):
tmp = []
for j in range(len(Available)):
tmp.append(Max[i][j] - Allocation[i][j])
Need.append(tmp)
print("初始可用资源:", Available)
Available, Max, Allocation, Need = bank_request(1, [1, 0, 2], Available, Max, Allocation, Need)
Available, Max, Allocation, Need = bank_request(4, [3, 3, 0], Available, Max, Allocation, Need)
6.2 死锁检测与解除代码
import copy
def deadlock_detect(available, allocation, need):
n = len(allocation)
m = len(available)
work = copy.deepcopy(available)
finish = [False] * n
while True:
find = False
for i in range(n):
if not finish[i]:
satisfy = True
for j in range(m):
if need[i][j] > work[j]:
satisfy = False
break
if satisfy:
for j in range(m):
work[j] += allocation[i][j]
finish[i] = True
find = True
if not find:
break
deadlock_proc = [i for i in range(n) if not finish[i]]
return len(deadlock_proc) > 0, deadlock_proc
def resolve_deadlock(dead_procs, allocation, available):
if not dead_procs:
return available, allocation
kill_pid = dead_procs[0]
print(f"终止进程P{kill_pid},回收资源")
for idx in range(len(available)):
available[idx] += allocation[kill_pid][idx]
allocation[kill_pid] = 0
return available, allocation
if __name__ == "__main__":
Available = [1, 0, 2]
Allocation = [[0, 1, 0],[2, 0, 0],[3, 0, 2],[2, 1, 1],[0, 0, 2]]
Need = [[7, 4, 3],[1, 2, 2],[6, 0, 0],[0, 1, 1],[4, 3, 1]]
has_deadlock, dead_list = deadlock_detect(Available, Allocation, Need)
if has_deadlock:
print(f"检测到死锁进程:{dead_list}")
Available, Allocation = resolve_deadlock(dead_list, Allocation, Available)
new_lock, new_list = deadlock_detect(Available, Allocation, Need)
print("解除后是否存在死锁:", new_lock)
七、应用场景
7.1 适用场景
- 嵌入式/实时工控系统:设备功能固定,进程与资源需求可提前预估
- 小型专用服务器、单机批处理系统:进程数量稳定,无频繁动态创建销毁
- 教学仿真平台:用于操作系统原理教学、算法实验演示
- 高可靠专用设备:医疗仪器、金融终端等零死锁要求的封闭系统
7.2 不适用场景
- 通用大型操作系统:进程动态变化,资源需求无法预判
- 高并发互联网、分布式系统:节点与请求海量,调度复杂
- 移动端、消费级应用软件:后台任务随机,资源管控难度大
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)