4. 速率单调调度(RMS):RMS原理、任务周期与优先级映射、RMS的可调度性分析

4.1 先聊聊RMS的直觉

速率单调调度,英文叫Rate Monotonic Scheduling,简称RMS。这名字听着挺唬人,其实说白了就一句话:任务周期越短,优先级越高

我刚开始接触实时系统时,觉得这规则也太简单了吧?后来在一条包装生产线上,我亲眼看到有人把周期长的任务设成了高优先级,结果短周期任务一直被阻塞,电机控制直接抖成了筛子。嗯,从那以后我再也不敢小看RMS了。

RMS是静态优先级调度里最经典的算法。它不需要你动态计算什么截止时间,也不需要你维护什么就绪队列的排序。你只需要在系统设计阶段,把每个任务的优先级定死,后面就按这个跑。

你想想看,这多省心?

4.2 RMS的核心原理

RMS的原理其实就一条铁律:任务的优先级与它的周期成反比。周期越短,优先级越高。

为什么这么定?因为短周期任务通常意味着更高的实时要求。比如一个1ms的电流环控制,和一个100ms的通信任务,谁更紧急?当然是电流环。如果通信任务抢了电流环的CPU时间,电机可能直接就过流了。

我在一个六轴机器人项目中就吃过这个亏。当时我把轨迹规划(周期50ms)设成了最高优先级,结果电流环(周期1ms)被频繁打断,机器人手臂在高速度下直接抖出了共振。后来改成RMS规则,电流环优先级最高,问题立刻解决。

RMS核心规则:
  • 每个任务有一个固定的周期 Ti
  • 每个任务有一个最坏情况执行时间 Ci
  • 优先级 Pi 与 Ti 成反比
  • 调度是抢占式的——高优先级任务可以打断低优先级任务

4.3 任务周期与优先级映射

优先级映射这件事,我习惯用一个简单的表格来梳理。假设我们有三个任务:

任务名称 周期 T (ms) 执行时间 C (ms) RMS优先级
电流环控制 1 0.2 最高(1)
速度环控制 5 0.5 中(2)
通信任务 100 2.0 最低(3)

你看,周期最短的电流环优先级最高,周期最长的通信任务优先级最低。这个映射关系一旦确定,在系统运行期间就不会再变了。

实际项目中,我一般会留一个「空闲任务」作为最低优先级。这个任务跑一些非实时的工作,比如日志记录、状态上报。这样即使所有实时任务都闲着,CPU也不会空转。

我的一个小技巧: 如果两个任务的周期非常接近(比如1ms和1.1ms),我会把周期更短的那个设成更高优先级。但如果周期完全一样,那就看谁更关键。这个判断需要你对业务有深刻理解。

4.4 RMS的可调度性分析

好,优先级定好了,任务也写完了。但你怎么知道这些任务一定能跑得过来?这就是可调度性分析要回答的问题。

RMS有一个经典的充分条件,叫刘-莱兰条件(Liu & Layland)。它说:对于n个周期任务,如果所有任务的CPU利用率满足下面这个公式,那么这些任务一定是可调度的:

U = Σ (C_i / T_i) ≤ n * (2^(1/n) - 1)

这个公式看着有点吓人,我刚开始学的时候也觉得头大。但实际用起来,我一般会先算一个利用率上限表:

任务数 n 利用率上限
1 1.000
2 0.828
3 0.779
4 0.756
5 0.743
→∞ ln 2 ≈ 0.693

当任务数无限多时,利用率上限趋近于69.3%。也就是说,如果你把所有任务的CPU利用率加起来不超过69%,那RMS一定能调度得过来。

但注意,这只是充分条件,不是必要条件。也就是说,即使利用率超过了这个上限,系统仍然有可能是可调度的。我遇到过不少项目,利用率跑到85%依然稳定运行。但作为工程师,我建议你保守一点,给自己留点余量。

避坑指南: 我曾经在一个项目中,算出来利用率只有65%,觉得稳了。结果一跑起来,某个任务的执行时间偶尔会超过最坏情况。这就是典型的「最坏情况估计不足」。记住,Ci 一定要取最坏情况,不是平均值。否则你的可调度性分析就是一张废纸。

4.5 一个完整的可调度性验证例子

咱们拿刚才那个三任务的例子来算一下:

任务1:C1=0.2ms, T1=1ms  → U1=0.2
任务2:C2=0.5ms, T2=5ms  → U2=0.1
任务3:C3=2.0ms, T3=100ms → U3=0.02

总利用率 U = 0.2 + 0.1 + 0.02 = 0.32

n=3时,利用率上限 = 3 * (2^(1/3) - 1) ≈ 0.779

0.32 ≤ 0.779 → 可调度!

这个结果说明,这三个任务在RMS调度下是安全的。但我在实际项目中,还会额外做一步:响应时间分析。因为利用率条件只是充分条件,而响应时间分析能给出更精确的结论。

响应时间分析的核心思想是:计算每个任务在最坏情况下的完成时间,看它是否小于等于它的截止时间(在RMS中,截止时间通常等于周期)。这个计算稍微复杂一些,需要迭代求解,但很多RTOS工具链都支持自动计算。

4.6 RMS的局限性

RMS不是万能的。我遇到过几个场景,RMS就不太合适:

  • 任务周期相差太大:比如一个1ms的任务和一个1000ms的任务,RMS会把1ms的任务优先级设得极高,但1000ms的任务可能永远得不到CPU时间——如果1ms任务一直占着CPU不放的话。不过这种情况在实际中很少见,因为短周期任务通常执行时间也很短。
  • 任务有共享资源:如果高优先级任务和低优先级任务共享同一个互斥锁,就可能出现优先级反转。这时候需要配合优先级继承协议或优先级天花板协议来解决。
  • 非周期任务:RMS只适用于周期任务。如果你的系统里有大量的事件驱动任务,那就要考虑其他调度算法了,比如EDF(最早截止时间优先)。
我的建议: 对于大多数工业运动控制系统,RMS已经足够用了。它简单、可靠、可预测。我做了十几年运动控制,90%的项目用的都是RMS。剩下的10%,要么是任务数太多(超过20个),要么是有复杂的资源依赖关系,才考虑用更复杂的调度算法。

4.7 本章知识体系

下面这张图,是我自己总结的RMS知识体系。你可以把它当作一个快速参考:

RMS速率单调调度知识体系 核心原理 优先级映射 周期越短 → 优先级越高 静态分配,运行不变 抢占式调度 可调度性分析 刘-莱兰条件 U ≤ n(2^(1/n)-1) 响应时间分析 最坏情况执行时间 局限性 周期相差过大 优先级反转 非周期任务不适用 需要配合协议使用 适用场景:工业运动控制、嵌入式实时系统

这张图把RMS的核心内容分成了三块:优先级映射、可调度性分析、局限性。我个人习惯在做系统设计时,先按这个框架走一遍,确保没有遗漏。

好了,关于RMS的内容就讲到这里。记住一句话:周期越短,优先级越高。这个原则虽然简单,但能解决你80%的实时调度问题。剩下的20%,靠经验和分析工具来补。

本章要点回顾:
  • RMS是静态优先级调度,优先级与周期成反比
  • 可调度性分析用刘-莱兰条件作为充分条件
  • 实际项目中要留余量,Ci 取最坏情况
  • 注意优先级反转问题,必要时使用优先级继承

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