RTOS调度机制:抢占、时间片与上下文切换
调度是 RTOS 的心脏。本文把星球里散落的调度问答串成一条主线:RTOS 为什么存在 → 三种调度方式 → tick 与时间片怎么配合 → 一次信号量唤醒的完整链路 → 与 Linux 调度的差别。
一、RTOS 为什么会出现:调度的动机
裸机小项目用"主循环轮询 + 中断响应"就够,但功能迭代后,任何模块的修改都容易干扰其他模块,中断越配越多、难度几何级上升。RTOS 本质上是个经过高手优化的调度器:IPC(队列、信号量、邮箱)本质上都是全局变量,RTOS 用统一的 API + 临界区保护换来了安全与解耦,代价是上下文切换消耗 CPU 时间。所以 RTOS 有个关键指标:任务切换自身花掉多少指令时间。见 RTOS为什么出现(Jack)。
二、抢占式、协作式与时间片
- 协作式调度:裸机主循环就是协作式——无法进行任务上下文切换(出栈入栈),必须当前程序块主动让出。见 老师,协作的话其实我们裸机的调度就是协作吧?协程,进程,线程这三个不太理解(Jack)。
- 抢占式调度:每个 systick 都检查是否有更高优先级任务就绪,有则立刻切换——这是通用 OS 做不到的实时性。见 抢占式调度和协作式调度 当你(Jack)、当Freertos以抢占式调度运行时,任务B(优先级低)正在运行,然后(Jack)。
- 时间片轮转:只对同优先级任务生效。抢占开启但时间片关闭时,同优先级的 A、B 之间谁不让出 CPU 谁就一直跑。见 关于抢占调度模式(时间片调度不(Jack)。
- 概念题版对照:抢占式调度即"进程从运行→就绪(被抢占)"时发生的调度。见 5. 什么是抢占式调度(。)。
三、SysTick、PendSV 与时间片的关系(最易混)
时间片和时间片中断是两码事:时间片固定为一个 tick(SysTick 周期),但 SysTick 到来时先做"高优先级抢占判断",再在同优先级间轮转。Jack 给过一个精确到毫秒的推演:A 运行 4ms 后 delay 阻塞 → PendSV 切到 B → t=10ms SysTick 发现 B、C 同优先级 → 切到 C → t=20ms 再切回 B。中间任务"用不满时间片"不会浪费,阻塞立刻让出。见 如果系统开始运行后,A任务运行了0.5S就DELAY阻塞(Jack)。
概念澄清:时间片 = 同优先级任务的轮流额度;SysTick = 产生节拍中断的定时器,ISR 里触发 PendSV,由 PendSV 通过切换 PSP 完成上下文切换。见 抢占模式下,每个systick 都会去判断有没有高优先级任务就绪,时间片是时间片(Jack)。
底层配合还有一环:SVC 指令产生高优先级 SVC 中断(进入内核态置位挂起位),而 PendSV 优先级被刻意配到最低,等所有中断退出后才真正切换任务。见 svc是个指令,会产生svc中断悬起,svc的中断优先级很高(Jack)。SysTick 之所以被设为 FreeRTOS 的时基、而 HAL 用另一个定时器做时基,正是为了避免两层计时在优先级上互相卡死,见 为什么Freertos时基用systick,然后HAL的时基要用另一个定时器(Jack)。
四、完整链路:一次信号量释放引发的调度
Jack 用 taskA(2ms)/taskB/idle 的逐帧分析把源码级流程走了一遍(见 释放信号量任务调度过程(taskA:2ms、taskB:阻塞、idle task):
- taskA 调
xQueueGenericSend释放信号量 → taskB 的 TCB 挂入就绪链表,比较优先级; - B 优先级更高且抢占开启 → 触发 PendSV →
vTaskSwitchContext挂载就绪链表中最高优先级任务; - B 处理完后在
xQueueReceive无数据 →vTaskPlaceOnEventList挂入延时/事件链表 → 切回 A; - A
vTaskDelay→ B 也阻塞 → idle 运行 → tick 到期后 A 被唤醒,循环往复。
这段是理解"就绪列表 + 延时列表 + PendSV"三者关系的最好素材。
五、调度规划与低功耗的交集
调度的反面是"没有可运行任务":所有业务任务都必须阻塞在通知/队列/信号量/有意义的延时上,系统才可能走到 idle → tickless。高频短任务会把连续空闲切碎、广播式唤醒会造成惊群,这些都属于调度设计的副作用。见 做嵌入式开发,低功耗设计几乎绕不开;带RTOS 的项目尤其如此(刘子奇)。另外 ISR 里绝不做任务调度,中断只做必要搬运——这也是 老师,协作的话其实我们裸机的调度就是协作吧?协程,进程,线程这三个不太理解 中强调的"任务"与"线程"称谓差异的实践背景:FreeRTOS 准确说是多任务(静态优先级 + 确定性切换),与通用 OS 的"线程"(时间片 + 动态优先级)不同。
六、对照:Linux 的调度复杂度
到了 Linux/Android,"调度"扩展成三层:摆核(大小核选核,EAS/HMP/负载均衡)、调频(DVFS 找能耗比最优点)、调度(调度类/策略/时机,选下一个 task)。只会改 task 优先级在量产产品上远远不够。见 进程调度 在所有操作系统中都很重要,不管是 FreeRTOS 还(Jason)。这正好解释了第五节的称谓问题:FreeRTOS 的"任务"更像裸机思维的延伸,而 Linux 的调度是资源管理问题。
来源笔记
- RTOS为什么出现 — Jack
- 老师,协作的话其实我们裸机的调度就是协作吧?协程,进程,线程这三个不太理解 — Jack
- 抢占式调度和协作式调度 当你 — Jack
- 当Freertos以抢占式调度运行时,任务B(优先级低)正在运行,然后 — Jack
- 关于抢占调度模式(时间片调度不 — Jack
-
- 什么是抢占式调度 — 。
- 如果系统开始运行后,A任务运行了0.5S就DELAY阻塞 — Jack
- 抢占模式下,每个systick 都会去判断有没有高优先级任务就绪,时间片是时间片 — Jack
- svc是个指令,会产生svc中断悬起,svc的中断优先级很高 — Jack
- 为什么Freertos时基用systick,然后HAL的时基要用另一个定时器 — Jack
- 1、Arm架构的中断优先级 正常配置 最大值就是15 这个是由芯片架构决定 — Jack
- 释放信号量任务调度过程(taskA:2ms、taskB:阻塞、idle task — Jack
- 做嵌入式开发,低功耗设计几乎绕不开;带RTOS 的项目尤其如此 — 刘子奇
- 进程调度 在所有操作系统中都很重要,不管是 FreeRTOS 还 — Jason