4. 任务调度策略详解:抢占式调度、时间片轮转调度、合作式调度
调度策略,说白了就是RTOS决定「下一个该谁跑」的规则。我做了这么多年嵌入式,见过不少工程师一上来就选抢占式,结果系统跑起来各种抖;也有人死磕合作式,最后发现实时性根本满足不了。其实没有银弹,关键看你的应用场景。
今天咱们就把这三种调度策略掰开揉碎,讲讲它们怎么工作、各自有什么坑、以及什么时候该用哪个。
4.1 抢占式调度(Preemptive Scheduling)
这是RTOS里最常用的策略。它的核心逻辑是:谁优先级高,谁就先跑。哪怕低优先级任务正在执行,只要高优先级任务就绪了,系统会立刻打断它,把CPU抢过来。
核心机制:每个任务都有优先级,调度器在每个系统Tick中断里检查是否有更高优先级的任务就绪。如果有,就做上下文切换。
我刚开始用FreeRTOS时,犯过一个低级错误:把两个中断服务函数里的任务优先级设得一样高,结果系统频繁切换,LED灯都在闪。后来才明白,抢占式调度对优先级设计的要求非常高。
适用场景
- 硬实时系统:比如电机控制、工业PLC,必须保证高优先级任务在确定时间内响应
- 事件驱动型系统:按键响应、传感器中断,需要立刻处理
- 多任务负载不均:有些任务偶尔才跑,但一跑就必须马上完成
我曾经踩过的坑:优先级反转。低优先级任务拿了互斥锁,高优先级任务等锁,结果中优先级任务一直跑,高优先级任务活活饿死。后来用优先级继承协议才解决。
4.2 时间片轮转调度(Round-Robin Scheduling)
这个策略就公平多了。所有同优先级任务轮流跑,每人分一个固定时间片。时间到了,不管任务跑没跑完,都得让给下一个。
说白了,就是「一人一筷子,轮流吃」。我习惯把时间片设成1ms到10ms之间,太短了切换开销大,太长了实时性又差。
适用场景
- 人机交互界面:LCD刷新、触摸扫描,不需要多快,但不能卡顿
- 后台任务:日志记录、状态监控、数据统计
- 同优先级任务较多:比如多个传感器轮流采集数据
我的经验:时间片轮转最适合「大家差不多重要」的场景。如果某个任务特别紧急,就别用轮转,给它单独提优先级。
4.3 合作式调度(Cooperative Scheduling)
这个策略最「佛系」。任务自己决定什么时候让出CPU,调度器从不主动打断。任务必须主动调用taskYIELD()或等待某个事件,才会切换。
你想想看,这就像一群人开会,每个人讲完了自己说「我讲完了,下一个」。如果有人一直讲不停,后面的人就只能干等。
适用场景
- 资源极度受限:RAM只有几KB的MCU,不需要内核维护Tick定时器
- 任务数量少且确定:比如一个采集任务、一个通信任务、一个显示任务
- 对确定性要求极高:没有抢占,就没有优先级反转,行为完全可预测
我曾经翻车的一次:在一个合作式系统里,有个任务里写了while循环等待外设就绪,结果外设一直没就绪,整个系统卡死了。从那以后,我规定合作式系统里绝不允许死等,必须用状态机。
4.4 三种策略对比
| 特性 | 抢占式 | 时间片轮转 | 合作式 |
|---|---|---|---|
| 实时性 | 高 | 中 | 低(取决于任务) |
| 资源开销 | 高(需要Tick中断、栈空间) | 中 | 低 |
| 编程复杂度 | 高(需处理优先级反转、竞态) | 中 | 低 |
| 公平性 | 差(高优先级独占) | 好 | 取决于任务设计 |
| 典型应用 | 电机控制、工业自动化 | GUI、后台服务 | 极简系统、裸机迁移 |
4.5 知识体系结构图
下面这张图帮你理清三种调度策略的核心逻辑和适用场景:
4.6 实际选型建议
嗯,这里我直接给结论吧:
- 做运动控制:必须用抢占式。电机换向、电流环这些任务,延迟1ms都可能出问题。
- 做人机界面:时间片轮转就够了。LCD刷新慢一点没关系,但不能卡死。
- 做传感器采集:如果MCU资源紧张,合作式调度配合状态机,反而更稳定。
我的习惯:实际项目中经常混合使用。比如抢占式调度跑实时任务,时间片轮转跑后台任务。FreeRTOS和uC/OS都支持这种混合模式。
最后说一句:调度策略没有绝对的好坏,只有合不合适。你想想看,一个跑在Cortex-M0上的温湿度采集器,非要上抢占式调度,那不是杀鸡用牛刀吗?
公众号:蓝海资料掘金营,微信deep3321