操作系统里的“最强风控”:银行家算法如何把死锁扼杀在摇篮里?

大家好!👋

提到“死锁”,学过操作系统的小伙伴肯定不陌生。它就像是两个倔脾气的人在吃饭,A手里拿着筷子等着B的碗,B手里端着碗等着A的筷子,两人谁也不肯先松手,结果就是谁也吃不上饭,最后一起“饿死”🍚。

那么,操作系统这位“大管家”该如何防止这种尴尬的场面发生呢?今天我们就来聊聊操作系统界最著名的“风控专家”——银行家算法


💰 为什么叫“银行家”算法?

这个算法最早由图灵奖得主艾兹格·迪杰斯特拉提出。之所以叫“银行家算法”,是因为它的逻辑和银行放贷简直一模一样。

想象一下,你是一家银行的行长,手里有一笔有限的资金。有几个客户(进程)来找你借钱,他们都提前告诉了你:“行长,我这一单生意最多需要借多少钱(最大需求)。”

作为精明的行长,你在批准一笔新的贷款时,绝不会把金库掏空。你会先在心里盘算一下:“如果我现在把钱借给他,我手里的流动资金(可用资源)还够不够让至少一个客户完成他的生意?只要有一个客户能做完,他就能连本带利把钱还给我,这样我就能把钱再借给下一个人,最终所有人都能圆满完成任务。”

如果算下来是安全的,你就放款;如果算下来会让自己陷入“破产”风险,你就只能对客户说:“亲,请您再等等哈。”


🧐 核心概念:什么是“安全状态”?

银行家算法的核心,就是确保系统始终处于安全状态

  • 安全状态:系统能找到至少一个安全序列(比如 ),按照这个顺序给进程分配资源,保证所有进程都能顺利执行完毕,不会发生死锁。

  • 不安全状态:找不到这样的序列。注意,不安全不等于已经死锁,但它意味着死锁的风险极高

为了做出判断,银行家算法手里有三本账(数据结构):

  • 最大需求矩阵(Max):每个进程事先声明的“我最多要多少资源”。

  • 已分配矩阵(Allocation):每个进程“手里已经拿到了多少资源”。

  • 可用资源向量(Available):系统金库里“目前还剩多少流动资金”。

还有一个隐藏的计算公式:

  • 需求矩阵(Need):每个进程“还需要多少资源才能完工”。

  • 公式:Need = Max - Allocation


🍳 举个栗子:一道经典的408考研真题

光说不练假把式,我们直接上干货!这是一道改编自计算机考研408统考的经典例题,非常考验基本功。

【题目背景】

某系统有3个进程P1、P2、P3,4种资源R1、R2、R3、R4。在T0时刻,系统的资源分配情况如下表所示:

最大需求矩阵(Max):

  • P1:[3, 2, 1, 4]

  • P2:[2, 2, 2, 2]

  • P3:[3, 3, 2, 3]

已分配矩阵(Allocation):

  • P1:[1, 1, 0, 2]

  • P2:[1, 0, 1, 1]

  • P3:[1, 2, 1, 0]

当前可用资源向量(Available):

  • [1, 1, 0, 0]

【问题】

请计算当前的需求矩阵(Need),并判断T0时刻系统是否处于安全状态?如果是,请给出一个安全序列。


📝 保姆级解题步骤

第一步:计算“需求矩阵(Need)”

根据公式:Need = Max - Allocation

  • P1还需要:[3-1, 2-1, 1-0, 4-2] = [2, 1, 1, 2]

  • P2还需要:[2-1, 2-0, 2-1, 2-1] = [1, 2, 1, 1]

  • P3还需要:[3-1, 3-2, 2-1, 3-0] = [2, 1, 1, 3]

整理一下当前的表格:

进程

Need (还缺)

Allocation (已有)

Available (系统剩余)

P1

[2, 1, 1, 2]

[1, 1, 0, 2]

[1, 1, 0, 0]

P2

[1, 2, 1, 1]

[1, 0, 1, 1]

P3

[2, 1, 1, 3]

[1, 2, 1, 0]

第二步:寻找安全序列(模拟放款过程)

我们要看手里的Available [1, 1, 0, 0] 能满足谁的需求?

  1. 第一轮扫描:

    • 看P1:Need是 [2, 1, 1, 2],Available是 [1, 1, 0, 0]。R1不够(1<2),R3也不够。P1不能执行。

    • 看P2:Need是 [1, 2, 1, 1],Available是 [1, 1, 0, 0]。R2不够(1<2)。P2不能执行。

    • 看P3:Need是 [2, 1, 1, 3],Available是 [1, 1, 0, 0]。R1不够(1<2)。P3不能执行。

等等!好像出问题了!

此时我们发现,当前的 Available [1, 1, 0, 0] 甚至无法满足任何一个进程的剩余需求(Need)。

  • P1缺R1,系统不够。

  • P2缺R2,系统不够。

  • P3缺R1,系统不够。

结论:

因为找不到任何一个进程可以立即获得所需资源并运行完毕,系统无法推进任何进程。这意味着T0时刻系统处于不安全状态(甚至已经死锁),不存在安全序列。

💡 重点提示:在很多教科书或考试题目中,如果算出“不安全状态”,答案就是“系统不安全,无安全序列”。但这道题作为“反面教材”非常经典,它告诉我们:如果银行家算法在分配资源前不进行检查,或者系统初始状态配置错误,就会直接掉进坑里。


🎓 408/高校期末模拟题(挑战一下!)

既然上面那个是不安全的,那我们来做一个安全的题目,巩固一下逻辑。

【题目】

设系统中有3种资源(A, B, C)和5个进程(P0~P4)。T0时刻状态如下:

  • Available = [3, 3, 2]

  • Allocation 和 Max 矩阵如下表:

进程

Max (最大需求)

Allocation (已分配)

P0

[7, 5, 3]

[0, 1, 0]

P1

[3, 2, 2]

[2, 0, 0]

P2

[9, 0, 2]

[3, 0, 2]

P3

[2, 2, 2]

[2, 1, 1]

P4

[4, 3, 3]

[0, 0, 2]

问题:

  1. 计算Need矩阵。

  2. 判断系统是否安全?若安全,给出一个安全序列。

【答案与解析】

1. 计算Need矩阵(Max - Allocation)

  • P0: [7, 4, 3]

  • P1: [1, 2, 2]

  • P2: [6, 0, 0]

  • P3: [0, 1, 1]

  • P4: [4, 3, 1]

2. 寻找安全序列

当前Available = [3, 3, 2]

  • 第一轮:

    • P0需要 [7, 4, 3] -> 不够

    • P1需要 [1, 2, 2] -> 够!(3≥1, 3≥2, 2≥2)。

    • P1执行,执行完后释放资源。

    • 新Available = 旧Available + P1的Allocation = [3, 3, 2] + [2, 0, 0] = [5, 3, 2]

    • 当前安全序列:

  • 第二轮(Available = [5, 3, 2]):

    • P0需要 [7, 4, 3] -> 不够

    • P2需要 [6, 0, 0] -> 不够(A资源5<6)

    • P3需要 [0, 1, 1] -> 够!

    • P3执行,释放资源。

    • 新Available = [5, 3, 2] + [2, 1, 1] = [7, 4, 3]

    • 当前安全序列:

  • 第三轮(Available = [7, 4, 3]):

    • P0需要 [7, 4, 3] -> 刚好够!

    • P0执行,释放资源。

    • 新Available = [7, 4, 3] + [0, 1, 0] = [7, 5, 3]

    • 当前安全序列:

  • 第四轮(Available = [7, 5, 3]):

    • P2需要 [6, 0, 0] -> 够!

    • P2执行,释放资源。

    • 新Available = [7, 5, 3] + [3, 0, 2] = [10, 5, 5]

    • 当前安全序列:

  • 第五轮:

    • 只剩P4,资源肯定够,执行P4。

    • 最终安全序列:

(注:安全序列可能不唯一,比如也是可能的,只要逻辑通顺即可)


📌 总结

银行家算法虽然听起来很复杂,但其实就是“借钱还钱”的道理。

  • 核心思想:分配资源前,先模拟一下,看看会不会导致以后没人能干活。

  • 关键点:只要系统里还有一个进程能拿到所有资源跑完并释放资源,系统就是安全的。

下次再遇到死锁问题,记得用“银行家”的思维去审视一下哦!💰

如果你觉得这篇推文有帮助,别忘了点赞、在看、转发三连! 👋

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐