第1章:任务调度机制——抢占式调度、时间片轮转、空闲任务、调度锁
大家好,我是你们的老朋友。今天咱们聊聊RTOS里最核心的东西——任务调度。
说实话,我刚开始做嵌入式那会儿,对调度机制的理解也就停留在“能跑就行”。直到有一次,一个按摩仪项目在客户手里频繁死机,我才真正意识到:不懂调度,你连Bug都找不到在哪。
这一章,咱们就把抢占式调度、时间片轮转、空闲任务和调度锁这四块硬骨头啃下来。别怕,我会用我踩过的坑给你铺路。
1.1 抢占式调度:谁优先级高谁先跑
抢占式调度,说白了就是“强者优先”。高优先级的任务一旦就绪,立马打断当前正在运行的低优先级任务,抢过CPU的使用权。
我习惯这么理解:就像你在排队打饭,突然来了个VIP客户,他可以直接插队到最前面。你虽然不爽,但规则就是这样。
核心要点:
- 每个任务都有一个优先级(数值越小优先级越高,或者反过来,看具体RTOS)
- 高优先级任务就绪时,立即发生任务切换
- 低优先级任务只有在高优先级任务阻塞或主动让出CPU时才能运行
我在项目中遇到过一个问题:一个按键扫描任务优先级设得太高,结果它一直占用CPU,导致电机控制任务响应延迟,按摩头卡住了。嗯,这就是典型的“优先级反转”前兆。
我的建议:优先级分配要遵循“紧急且短”的任务高优先级,“不紧急或长”的任务低优先级。比如按键响应可以高,但LED闪烁就放低。
1.2 时间片轮转:大家轮流用CPU
如果所有任务优先级都一样呢?那就用时间片轮转。
每个任务分配一个固定的时间片(比如10ms),时间到了就切换到下一个任务。你想想看,这就像几个朋友轮流开车,每人开10分钟,公平合理。
时间片轮转的典型场景:
- 多个同等重要的后台任务(比如数据采集、日志记录)
- 没有明确优先级差异的用户界面刷新
- 调试阶段,避免某个任务饿死
我记得有一次调试一个按摩仪,三个传感器采集任务优先级相同,但其中一个采集时间特别长。结果另外两个任务老是抢不到CPU,数据丢失严重。后来我把它们改成时间片轮转,每个任务给5ms,问题就解决了。
注意:时间片太短会导致频繁切换,浪费CPU在上下文切换上;时间片太长又会让其他任务等太久。一般建议在1ms~20ms之间,具体看你的系统时钟节拍。
1.3 空闲任务:CPU没事干的时候
当所有任务都阻塞或挂起时,CPU总不能空转吧?这时候空闲任务就登场了。
空闲任务是RTOS自动创建的,优先级最低,永远处于就绪状态。它的主要职责是:
- 让CPU进入低功耗模式(比如WFI指令)
- 统计CPU利用率
- 做一些系统级的清理工作
我曾经犯过一个低级错误:在空闲任务里加了一个延时函数,结果系统功耗反而升高了。为什么?因为空闲任务本该让CPU睡觉,结果它自己在那数数,CPU根本睡不了。
避坑指南:空闲任务里不要做任何阻塞操作!不要加延时!不要加死循环!让它干干净净地调用休眠指令就好。
1.4 调度锁:关键时刻的“暂停键”
调度锁,说白了就是临时关闭任务调度。你可能会问:为什么要关调度?
想象一下这个场景:你在更新一个全局变量,刚写到一半,突然被高优先级任务打断,它也来读写这个变量——数据就乱套了。
这时候,调度锁就派上用场了。它告诉RTOS:“先别切换任务,等我干完这点活再说。”
使用调度锁的典型场景:
- 保护临界区代码(比如操作共享变量)
- 需要原子操作的硬件配置序列
- 避免中断和任务之间的竞态条件
重要原则:调度锁要快进快出!锁住的时间越短越好,一般不超过几十微秒。我曾经见过一个同事把调度锁一锁就是100ms,结果系统响应直接崩了。
代码示例(以FreeRTOS为例):
// 进入临界区,关闭调度
taskENTER_CRITICAL();
// 这里操作共享变量,安全!
g_motor_speed = 100;
g_motor_direction = 1;
// 退出临界区,恢复调度
taskEXIT_CRITICAL();
警告:调度锁内不要调用任何可能阻塞的函数(比如延时、等待信号量)。否则系统会直接死锁,连空闲任务都救不了你。
小结一下
这一章咱们聊了四种调度机制:
| 机制 | 核心思想 | 典型用途 |
|---|---|---|
| 抢占式调度 | 高优先级打断低优先级 | 实时性要求高的任务 |
| 时间片轮转 | 同优先级任务轮流执行 | 后台批量处理 |
| 空闲任务 | CPU无事可做时运行 | 低功耗、统计CPU利用率 |
| 调度锁 | 临时关闭任务切换 | 保护临界区、原子操作 |
我个人觉得,理解这四种机制,你就掌握了RTOS调度的80%。剩下的20%,是在实际项目中慢慢磨出来的。
下一章,咱们聊聊任务状态与状态切换——为什么任务会“卡住”?怎么让它“活过来”?到时候见。
课后小作业:打开你的RTOS工程,看看空闲任务的钩子函数里有没有加延时?如果有,试着去掉,测一下功耗变化。你会回来感谢我的。
公众号:蓝海资料掘金营,微信deep3321