调度器到底做什么

RTOS 调度器是内核的心脏。它每毫秒决定"现在该跑哪个任务"。核心原则很简单:永远跑最高优先级的就绪任务。但实际工程中,优先级怎么分配、任务之间怎么共享资源、高优先级被低优先级堵住怎么办,这些才是真正的坑。

调度器不是越复杂越好。简单的抢占式优先级调度,配合合理的优先级划分,能解决 90% 的实时问题。
RTOS 调度配图:中央芯片周围多层级发光横向通道辐射展开
多层优先级的任务调度

这篇讲 RTOS 调度的核心概念和实战踩坑。

抢占式与协作式

两种调度方式:

调度方式对比
  • 抢占式高优先级任务就绪立刻抢 CPU,实时性好。
  • 协作式任务主动让出 CPU,简单但实时性差。
  • 混合大部分抢占,关键段关中断临界区。
// FreeRTOS 创建任务
xTaskCreate(vHighTask, "High", 256, NULL, 3, NULL);  // 优先级 3
xTaskCreate(vLowTask, "Low", 256, NULL, 1, NULL);   // 优先级 1
// HighTask 一就绪就抢占 LowTask

优先级翻转

优先级翻转是 RTOS 最经典的坑。场景:高优先级任务 H 等低优先级任务 L 释放信号量,但中等优先级任务 M 一直跑,把 L 堵在后面,H 等不到信号量,实际变成 M 在跑。H 的优先级被 L 间接拉低了。

// 问题场景:
// H (prio 3) 等 mutex
// L (prio 1) 持有 mutex,但被 M (prio 2) 抢占
// M 一直跑 -> L 跑不完 -> 不释放 mutex -> H 永远等
// H 的实际响应时间 = M 的运行时间

优先级继承

解决办法:优先级继承(Priority Inheritance)。L 持有 mutex 时,临时把 L 的优先级提升到 H 的级别,让 L 尽快跑完释放 mutex,然后降回去。

// FreeRTOS 使用带优先级继承的互斥量
SemaphoreHandle_t m = xSemaphoreCreateMutex();
xSemaphoreTake(m, portMAX_DELAY);   // 持有期间优先级被继承提升
// 做关键操作
xSemaphoreGive(m);                  // 释放后优先级降回

注意:递归互斥量(Recursive Mutex)允许同一任务多次 take。