4. 调度机制:抢占式调度、时间片轮转、空闲任务、调度策略对比
调度机制,说白了就是操作系统怎么决定「下一个该谁干活了」。
在暖通空调这种实时系统里,调度策略选错了,轻则温度波动大,重则压缩机直接罢工。我见过不少项目,硬件选型没问题,代码逻辑也对,就是调度策略没选对,结果系统跑起来一塌糊涂。
今天咱们就把这几种调度机制掰开揉碎了讲清楚。
4.1 抢占式调度
抢占式调度,核心就一句话:高优先级的任务来了,低优先级的立马让路。
举个例子。你正在写一个温度采集任务,优先级设成了中等。突然来了一个压缩机保护任务,优先级最高。这时候,操作系统会直接打断温度采集,先把保护任务跑完,再回来继续采集。
为什么会这样?因为压缩机保护是硬实时任务,晚处理一毫秒都可能烧设备。
我在项目中遇到过这种情况:一个新风系统的控制器,用了非抢占式调度。结果风机调速任务占着CPU不放,温度传感器报警一直没被处理,最后压缩机过载保护跳了。换成抢占式调度后,问题立刻解决。
抢占式调度的特点:
- 响应时间可预测,高优先级任务几乎不会被阻塞
- 适合硬实时任务,比如压缩机保护、过流检测
- 需要小心优先级反转问题
注意:抢占式调度不是万能的。如果高优先级任务太多,低优先级任务可能永远得不到CPU时间,这叫「饥饿」现象。我曾经调试一个多联机系统,就是因为一个高优先级的通信任务频繁抢占,导致温度PID调节任务一直跑不起来,房间温度忽高忽低。
4.2 时间片轮转
时间片轮转,说白了就是「大家轮流来,每人分一段固定时间」。
每个任务分配一个时间片,比如10毫秒。时间到了,操作系统强制切换下一个任务。这样所有任务都能得到执行机会,谁也别想独占CPU。
我建议在暖通空调系统中,把那些非关键但需要定期执行的任务放在时间片轮转里。比如:
- 人机界面刷新(不需要实时响应)
- 历史数据记录(晚几秒没关系)
- 网络心跳包发送
时间片轮转有个好处:系统负载均衡。不会出现某个任务饿死的情况。
但要注意时间片大小的选择。太短了,频繁切换上下文,CPU开销大。太长了,响应延迟高。我个人习惯是设10-20毫秒,具体看任务数量。
技巧:如果你用的是FreeRTOS,时间片轮转默认是开启的。但要注意,同优先级的任务才会轮转。不同优先级之间,还是抢占式调度优先。
4.3 空闲任务
空闲任务,就是CPU没事干的时候跑的那个任务。
很多人觉得空闲任务不重要,其实不然。在暖通空调系统里,空闲任务可以做很多事:
- 进入低功耗模式,省电
- 统计CPU利用率
- 做一些后台自检
我记得有一次调试一个楼宇空调系统,发现功耗比预期高很多。查了半天,发现是空闲任务里没做休眠处理,CPU一直在空转。加上WFI指令后,功耗直接降了40%。
空闲任务的优先级通常是最低的。只有所有其他任务都阻塞或就绪时,才会执行空闲任务。
空闲任务的典型用法:
void vApplicationIdleHook(void)
{
// 进入低功耗模式
__WFI(); // Wait For Interrupt
// 或者统计CPU空闲时间
idle_counter++;
}
注意:不要在空闲任务里做耗时操作。比如延时、复杂计算。因为空闲任务执行时,其他任务可能正在等待CPU。你占着空闲任务不放,其他任务就得不到执行。
4.4 调度策略对比
三种调度策略各有适用场景。我整理了一个对比表,方便你选型时参考:
| 特性 | 抢占式调度 | 时间片轮转 | 空闲任务 |
|---|---|---|---|
| 响应时间 | 快,可预测 | 中等,取决于时间片 | 最慢(优先级最低) |
| 适用场景 | 硬实时任务 | 软实时任务 | 后台任务、省电 |
| 优先级要求 | 需要合理分配优先级 | 同优先级任务 | 最低优先级 |
| 风险 | 优先级反转、饥饿 | 上下文切换开销大 | 不能做耗时操作 |
| 典型应用 | 压缩机保护、过流检测 | 人机界面、数据记录 | 低功耗管理、CPU统计 |
实际项目中,这三种策略往往是混合使用的。比如:
- 压缩机保护任务用抢占式调度,优先级最高
- 温度采集任务用时间片轮转,保证定期执行
- 空闲任务里做低功耗处理
我曾经在一个中央空调控制器项目里,就是这种混合方案。效果很好,系统响应快,功耗也低。
选型建议:
- 先列出所有任务,标注实时性要求
- 硬实时任务(响应时间<1ms)用抢占式,优先级最高
- 软实时任务(响应时间10-100ms)用时间片轮转
- 后台任务放空闲任务里
- 定期检查CPU利用率,避免任务过多导致调度延迟
嗯,调度机制这块就讲这么多。说白了,没有最好的调度策略,只有最适合你项目的策略。选对了,系统跑得稳;选错了,调试起来够你喝一壶的。