2. RTOS基础回顾

好,咱们进入第二章。这一章是RTOS的骨架,也是你后面做协议栈适配时绕不开的基础。任务调度、状态机、优先级、抢占——这四个词几乎能解释RTOS里90%的行为。我当年刚接触RTOS时,就是被这几个概念绕晕过,后来踩了几个坑才真正理解它们是怎么配合的。

任务调度:谁来决定下一个跑谁?

说白了,调度器就是RTOS的大脑。它决定当前哪个任务获得CPU的使用权。你想想看,单核CPU同一时刻只能跑一个任务,但RTOS能让你感觉多个任务在“同时”运行——这就是调度器在背后快速切换。

常见的调度策略就两种:

  • 时间片轮转(Round-Robin):每个任务轮流跑一个固定时间片,跑完就换人。适合同等优先级的任务。
  • 优先级调度(Priority-Based):谁优先级高谁先跑。这是RTOS的主流做法。

我在一个物联网网关项目里,就遇到过因为调度策略选错导致数据丢包的情况。当时用了纯时间片轮转,结果高优先级的网络接收任务经常被低优先级的传感器采集任务打断,缓冲区溢出。后来换成优先级调度,问题立刻解决。

核心原则:实时系统里,时间确定性比吞吐量更重要。优先级调度能保证紧急任务及时响应,但代价是低优先级任务可能被饿死。

任务状态机:任务的一生

每个任务在RTOS里都有生命周期。我习惯把任务状态机画成一张图,这样调试时心里有数。常见的状态就四个:

状态 含义 典型触发条件
就绪(Ready) 任务已准备好运行,只等CPU 创建完成、被唤醒、时间片用完
运行(Running) 正在占用CPU执行 调度器选中该任务
阻塞(Blocked) 等待某个事件或资源 等待信号量、消息队列、延时
挂起(Suspended) 被强制暂停,不参与调度 调用挂起API、调试暂停

嗯,这里要注意:阻塞和挂起看起来都像“暂停”,但本质不同。阻塞是任务主动让出CPU等资源,一旦条件满足会自动回到就绪态;挂起是被动行为,必须由其他任务或中断来恢复它。

RTOS任务状态机 就绪 (Ready) 运行 (Running) 阻塞 (Blocked) 挂起 (Suspended) 调度器选中 时间片用完/被抢占 等待资源 资源就绪 挂起API 恢复API 阻塞是主动等待,挂起是被动暂停——调试时别搞混了

任务优先级:谁更重要?

优先级是RTOS里最敏感的配置。设高了怕影响其他任务,设低了怕响应不及时。我个人习惯把优先级分成三层:

  • 高优先级(0-5):留给中断处理、时间关键型任务,比如网络协议栈的接收线程。
  • 中优先级(6-10):普通周期性任务,比如传感器采集、状态上报。
  • 低优先级(11-15):后台任务、空闲处理、日志输出。

经验之谈:别把优先级设得太密集。比如0-15共16级,我通常只用5-6个级别,每级之间留出缓冲。太密集的优先级反而容易引发优先级反转问题。

说到优先级反转,这是个经典坑。我曾经在一个多传感器融合项目里,低优先级的温度采集任务占着I2C总线不放,中优先级的显示任务一直抢CPU,结果高优先级的姿态解算任务拿不到总线——整个系统卡死。后来用优先级继承协议才解决。

抢占机制:说停就停的能力

抢占是RTOS和裸机最大的区别。裸机里中断能打断主循环,但任务之间没有打断关系。RTOS里,只要一个高优先级任务就绪,调度器会立刻暂停当前运行的低优先级任务,把CPU交给高优先级任务。

抢占的触发点通常有三个:

  1. 中断退出时:中断服务程序结束后,调度器检查是否有更高优先级的任务就绪。
  2. 任务主动挂起或阻塞时:比如调用延时或等待信号量,调度器趁机切换。
  3. 时间片到期时:当前任务的时间片用完,调度器强制切换。

注意:抢占虽然好,但滥用会导致“优先级抖动”。如果一个高优先级任务频繁就绪又频繁阻塞,系统会花大量时间在上下文切换上,实际有效计算时间反而减少。我曾经在一个视频处理项目里,把网络接收任务的优先级设得太高,结果CPU 30%的时间都在切任务——得不偿失。

上下文切换:抢占的代价

每次抢占都伴随着上下文切换。说白了,就是把当前任务的寄存器、堆栈指针、状态字保存起来,再恢复下一个任务的现场。这个过程是纯开销,不产生任何业务价值。

我一般用这个公式估算切换开销:

切换时间 = 保存现场时间 + 调度决策时间 + 恢复现场时间

在Cortex-M3上,一次完整的上下文切换大约需要1-3微秒(取决于内核实现)。如果你的系统有10个任务,每秒切换1000次,那光切换就吃掉1-3%的CPU——看起来不多,但在硬实时系统里,这1%可能就是生死线。

实战建议:怎么配优先级和抢占?

好,讲完理论,给点实在的。我在做协议栈适配时,总结了一套优先级配置原则:

  • 中断服务线程优先级最高:协议栈的接收中断必须第一时间响应。
  • 协议栈处理线程次之:比如TCP/IP的协议处理、重传定时器。
  • 应用任务再次之:业务逻辑可以容忍一点延迟。
  • 调试/日志任务最低:别让打印日志拖慢系统。

另外,我建议你在项目初期就画一张任务优先级映射表,明确每个任务的优先级、周期、最大执行时间。这张表在后续调试和性能优化时能救命。

一句话总结:调度器决定谁跑,状态机描述任务在哪,优先级决定谁更重要,抢占保证紧急任务能插队。这四个机制配合好了,你的RTOS系统就稳了。