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 图来总结本章的核心逻辑。你可以把它当作一个「知识地图」,方便回顾。

固定优先级调度(FPS)知识体系 固定优先级调度 RMS 算法 DMS 算法 优先级反转 周期越短,优先级越高 利用率 ≤ n(2^(1/n)-1) 截止时间越短,优先级越高 响应时间分析法 低优先级阻塞高优先级 解决方案 优先级继承 优先级天花板 核心:确定性 + 可调度性分析 + 避免优先级反转

这张图把 RMS、DMS 和优先级反转的关系梳理清楚了。你想想看,这三个知识点其实是环环相扣的——RMS 和 DMS 解决「谁先跑」的问题,优先级反转解决「跑不动」的问题。

最后提醒一句: 固定优先级调度虽然简单,但优先级反转是个隐藏的坑。我见过太多项目因为没处理好这个问题,导致系统在关键时刻掉链子。记住——用互斥锁的地方,一定要考虑优先级继承或天花板机制


公众号:蓝海资料掘金营,微信deep3321