死锁、饥饿与优先级反转 — 专题笔记

← 操作系统知识地图


基本概念

概念一句话
死锁多个进程互相等待对方持有的资源,谁也无法推进
饥饿某个进程因资源分配策略不公平,长期得不到所需资源
安全序列一个进程执行顺序(比如****),按此顺序每个进程执行时,前面进程释放的资源足够满足它的剩余需求,最终所有进程都能完成
优先级反转高优先级任务被低优先级任务阻塞(低优先级持有锁,中优先级抢走 CPU)

死锁四必要条件(缺一不可):

条件含义破坏方式
互斥资源只能被一个进程独占难破坏,很多资源本质就是互斥的
不可剥夺已分配资源不能被强制抢走允许系统抢占(如 CPU、内存换出)
请求并保持拿着旧资源等新资源一次性申请全部所需资源
循环等待形成 的等待环资源编号,强制按递增顺序申请

每类资源只有一个实例时,资源分配图中的环 ⇔ 死锁的充要条件。多实例时环是必要但不充分。

避免死锁 — 银行家算法

安全状态:存在一个执行序列,序列中每个进程执行时,前面所有进程释放的资源总量能满足它剩余的 Need。

核心变量

变量维度含义关系
Maxn×m 矩阵进程最多需要各类资源的数量已知常量
Allocationn×m 矩阵进程当前已占用的各类资源数初值给定,分配时增加
Needn×m 矩阵进程还需要的各类资源数Need = Max - Allocation
Availablem 维向量系统当前空闲的各类资源数分配时减少,归还时增加

安全性检测

题目形式:给 Max + Allocation + 若干候选 Available,判断哪些安全。

操作流程:

① Need = Max - Allocation               // 逐进程减,得需求表
② 找 Need[i] ≤ Available 的进程(每个分量都要 ≤)
   ├─ 找到 → ③
   └─ 找不到 → 不安全,死锁
③ 执行该进程:Available += Allocation[i]   // 归还全部已分配资源
④ 重复②~③,直到所有进程都执行完 → 安全

演练速查:

Available 初始首步可执行归还后 Available能否走完
(1, 4, 0)(2, 7, 5)✅ 安全
(0, 6, 2)(0, 6, 5)❌ 需 B=7、 需 A=1 都无法满足
(1, 1, 1), (2, 4, 9)❌ 剩下进程 B 类需求 ≥6,可用 B=4
(0, 4, 7)(0, 4, 10)❌ 需 A=1,可用 A=0

死锁检测(资源分配图化简法)

不断找当前能继续执行的进程(Need ≤ Available),假设它执行完释放资源,删去它所有的边。最终图可完全化简 → 无死锁;不可化简 → 有死锁。

与安全性检测的区别:检测不关心 Max,只看当前 Allocation 和 Available。

死锁解除

方法做法代价
资源剥夺从其他进程强制抢资源给死锁进程被剥夺进程受损
撤销进程终止死锁中的一个或多个进程丢失已完成的工作
进程回退回滚到死锁前的检查点需检查点机制支持

优先级反转

产生条件:低优先级任务持有锁 → 中优先级任务抢占 CPU → 高优先级任务等锁,被中优先级任务阻塞。

解决方法:

  • 优先级继承:持锁的低优先级任务临时继承等待者的高优先级,把中优先级压住不让插队,持锁任务尽快执行完释放锁。关键点:必须由 OS 在锁上做——普通信号量只排他、不做继承,所以 RTOS 里用互斥量这种”自带优先级继承的锁”(FreeRTOS 的具体实现见 书—FreeRTOS 互斥量)。注意:继承能消反转,但不能防死锁——H 等 L、L 又等 H 照样僵死。
  • 优先级天花板:进入临界区就把任务提到该临界区能到达的最高优先级(一次性抬满,避免链式继承)。

加锁 / 解锁纪律(工程上防死锁)

理论上是破坏”循环等待”(见上表),落到工程代码就是两条硬纪律:

  • 加锁顺序全局一致:多把锁嵌套时,全系统按同一约定顺序获取(如资源编号递增 / 从低到高),让等待关系永远单向、不成环
  • 解锁按相反顺序:先拿 L1 再拿 L2,就 L2 → L1 释放(LIFO)。它本身不能单独防死锁(那是加锁顺序的职责),但能让嵌套锁不散乱、好排查,是配套卫生习惯
  • 拿多个资源别死等:用 trylock 或带超时获取,拿不到就先放手已持有的锁,避免拿着旧锁等新锁卡住别人