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统计

实际项目中,这三种策略往往是混合使用的。比如:

  • 压缩机保护任务用抢占式调度,优先级最高
  • 温度采集任务用时间片轮转,保证定期执行
  • 空闲任务里做低功耗处理

我曾经在一个中央空调控制器项目里,就是这种混合方案。效果很好,系统响应快,功耗也低。

选型建议:

  1. 先列出所有任务,标注实时性要求
  2. 硬实时任务(响应时间<1ms)用抢占式,优先级最高
  3. 软实时任务(响应时间10-100ms)用时间片轮转
  4. 后台任务放空闲任务里
  5. 定期检查CPU利用率,避免任务过多导致调度延迟

嗯,调度机制这块就讲这么多。说白了,没有最好的调度策略,只有最适合你项目的策略。选对了,系统跑得稳;选错了,调试起来够你喝一壶的。