4. 固定优先级调度(FPS):速率单调调度(RMS)算法、截止时间单调调度(DMS)算法、优先级反转问题
各位同学,今天我们来聊聊实时控制里最经典的一类调度策略——固定优先级调度。说白了,就是每个任务在系统启动前就定死了优先级,运行过程中谁也不许改。这种做法简单、高效,在工业控制领域用得特别多。
我个人习惯把固定优先级调度比作「排队买票」——有人是VIP通道,有人是普通通道,通道一旦定好,就不能临时换。你想想看,这种确定性对实时系统来说有多重要?
4.1 速率单调调度(RMS)算法
RMS 是固定优先级调度里最经典的算法。它的规则特别简单:任务的周期越短,优先级越高。
为什么这么定?我举个例子你就明白了。假设有两个任务:任务A每10ms跑一次,任务B每100ms跑一次。A来得更频繁,如果A的优先级低,它可能被B堵住,导致A错过截止时间。而A的截止时间通常更紧,所以让A优先执行是合理的。
RMS 的核心思想: 周期越短 → 优先级越高 → 越早被调度执行。
RMS 有一个重要的可调度性判定条件。对于 n 个独立任务,如果满足:
∑ (Ci / Ti) ≤ n * (2^(1/n) - 1)
其中 Ci 是任务执行时间,Ti 是任务周期。当 n 很大时,右边趋近于 ln2 ≈ 0.693。也就是说,CPU 利用率不超过 69.3% 时,RMS 一定能保证所有任务按时完成。
我在项目中遇到过这样一个坑:有个系统有 5 个周期任务,算下来 CPU 利用率刚好 68%,理论上没问题。但实际跑起来,偶尔会丢数据。查了半天才发现,有个中断服务程序没算进任务集里,它偷偷占了 5% 的 CPU 时间。嗯,这里要注意——RMS 的利用率计算必须包含所有抢占源。
实战建议: 用 RMS 时,建议把 CPU 利用率控制在 60% 以下,留出余量给中断和突发任务。我一般会留 20% 的余量,这样系统更皮实。
4.2 截止时间单调调度(DMS)算法
DMS 是 RMS 的推广版本。RMS 只看周期,但有些任务的截止时间并不等于周期。比如一个任务每 50ms 跑一次,但要求 30ms 内完成。这时候 RMS 就不太合适了。
DMS 的规则是:截止时间越短,优先级越高。说白了,谁更急,谁先跑。
我做过一个电机控制项目,里面有个电流环任务,周期 100μs,但截止时间只有 50μs。如果用 RMS,它和另一个周期 80μs 的任务比,优先级反而低。但实际上电流环更紧急。换成 DMS 后,问题就解决了。
| 算法 | 优先级依据 | 适用场景 |
|---|---|---|
| RMS | 任务周期 | 截止时间 = 周期的任务 |
| DMS | 任务截止时间 | 截止时间 ≠ 周期的任务 |
DMS 的可调度性判定比 RMS 复杂一些。对于独立任务,可以用响应时间分析法:
R_i = C_i + ∑ (ceil(R_i / T_j) * C_j) (j ∈ hp(i))
其中 hp(i) 是优先级高于任务 i 的任务集合。这个公式需要迭代计算,直到 R_i 收敛。如果 R_i ≤ D_i,则任务可调度。
注意: DMS 和 RMS 都是固定优先级调度,但 DMS 更灵活。不过 DMS 的优先级分配需要知道每个任务的截止时间,如果截止时间不确定,那就只能用 RMS 了。
4.3 优先级反转问题
优先级反转,说白了就是「低优先级任务堵住了高优先级任务」。这是固定优先级调度里最头疼的问题,没有之一。
我来讲一个经典场景:有三个任务,优先级从高到低分别是 H、M、L。L 先运行,拿到了一个共享资源(比如一个互斥锁)。然后 H 就绪了,它也想用这个资源,但被 L 占着,所以 H 被阻塞。这时候 M 就绪了,它不需要这个资源,但它的优先级比 L 高,所以 M 抢占了 L。结果呢?H 被 M 和 L 一起堵住,优先级完全颠倒了。
为什么会这样?因为固定优先级调度只考虑任务本身的优先级,不考虑资源依赖。H 虽然优先级最高,但被低优先级的 L 和 M 间接阻塞了。
优先级反转的后果: 高优先级任务的响应时间可能无限延长,导致错过截止时间。在航天、医疗等安全关键系统中,这是致命的。
我曾经在一个无人机飞控项目里遇到过这个问题。有个传感器数据采集任务优先级很高,但偶尔会被一个日志记录任务堵住,导致控制周期抖动。查了两天才定位到是优先级反转。
4.4 解决方案:优先级继承与优先级天花板
解决优先级反转,主流方案有两个:优先级继承和优先级天花板。
优先级继承: 当高优先级任务被低优先级任务阻塞时,低优先级任务临时「继承」高优先级任务的优先级。这样它就不会被中间优先级的任务抢占了。等释放资源后,优先级恢复原样。
我习惯用优先级继承,因为它实现简单,而且只在发生阻塞时才生效,对系统性能影响小。很多实时操作系统(如 FreeRTOS、VxWorks)都支持这个机制。
优先级天花板: 每个共享资源都有一个「天花板优先级」,等于所有可能使用该资源的任务中的最高优先级。任务在获取资源时,优先级被提升到天花板级别。这样能避免死锁,但实现起来稍微复杂一些。
| 方案 | 优点 | 缺点 |
|---|---|---|
| 优先级继承 | 实现简单,只在阻塞时生效 | 可能发生链式阻塞 |
| 优先级天花板 | 避免死锁,响应时间更可控 | 实现复杂,需要静态分析 |
我的建议: 如果系统任务数量不多(比如 10 个以内),用优先级继承就够了。如果任务多、资源多,建议用优先级天花板,或者干脆用无锁数据结构。
4.5 知识体系结构图
下面我用一张 SVG 图来总结本章的核心逻辑。你可以把它当作一个「知识地图」,方便回顾。
这张图把 RMS、DMS 和优先级反转的关系梳理清楚了。你想想看,这三个知识点其实是环环相扣的——RMS 和 DMS 解决「谁先跑」的问题,优先级反转解决「跑不动」的问题。
最后提醒一句: 固定优先级调度虽然简单,但优先级反转是个隐藏的坑。我见过太多项目因为没处理好这个问题,导致系统在关键时刻掉链子。记住——用互斥锁的地方,一定要考虑优先级继承或天花板机制。
公众号:蓝海资料掘金营,微信deep3321