02-任务调度与状态管理.md 6.4 KB


tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — FreeRTOS基础知识" author: "尚硅谷研究院" date: 2026-07-17

created: 2026-07-17

任务调度与状态管理

用生活理解:CPU 像一个只能同时接待一位顾客的收银员。多任务系统让收银员在多个顾客之间快速切换,让每个顾客都觉得自己被"同时"服务着。调度器就是排号系统——谁优先级高谁先结账,同优先级按顺序来。

多任务处理

Basic concept

内核是操作系统的核心组件。多任务操作系统通过任务之间的快速切换,在单核处理器上制造出"并发执行"的假象。

实际上,单核 CPU 在同一时刻只能运行一个任务。任务切换的速度非常快(毫秒级),让人感觉多个任务在同时运行。

多任务逻辑并发 vs 实际执行

多任务系统的好处:

  • 将复杂应用拆分为一组更小、更易管理的任务
  • 便于团队分工和代码复用
  • 时序和排序细节从应用代码中剥离,由 OS 负责

任务调度

Working principle

调度器是内核中负责决定"下一时刻运行哪个任务"的组件。调度策略是决定算法。

FreeRTOS 默认使用固定优先级的抢占式调度策略,对同等优先级任务执行时间片轮询

Scheduling modes

模式 说明 适用场景
抢占式调度 高优先级任务随时可以抢占正在执行的低优先级任务 需要确保高优先级任务实时响应的场景
时间片轮询 同优先级任务轮流执行固定长度的时间片 多任务需要公平分配 CPU 的场景

抢占式调度

高优先级任务在等待资源(延时、信号量等)时会主动让出 CPU,调度器选择其他就绪的高优先级任务执行,不会让低优先级任务"饿死"。

时间片轮询调度

Cooperative scheduling

除了抢占式调度,FreeRTOS 也支持协程式调度(configUSE_PREEMPTION = 0 时启用)。在协程式调度下,任务不会被强制打断,只有当任务主动调用 taskYIELD() 或阻塞等待时,调度器才会切换任务。协程式调度实时性较弱,一般不推荐使用。

任务状态

Four task states

FreeRTOS 中任务共存在 4 种状态:

状态 含义 进入方式 退出方式
运行态(Running) 任务正在执行 调度器选中 被抢占、阻塞、挂起
就绪态(Ready) 任务可执行但未运行 创建、解除阻塞、解挂 被调度器选中
阻塞态(Blocked) 等待延时或外部事件 vTaskDelay、等待队列/信号量等 延时到、事件发生
挂起态(Suspended) 类似暂停 vTaskSuspend() vTaskResume() 解挂

State transitions

只有就绪态可以转变为运行态。其他状态的任务想要运行,必须先转变为就绪态。

任务状态转换图

滴答计数器

Working principle

FreeRTOS 实时内核通过滴答计数变量(Tick Count)测量时间。SysTick 定时器中断以固定频率递增滴答数,每次中断称为一个 RTOS 滴答

每次滴答中断时,内核检查是否有任务需要解除阻塞或唤醒。如果需要,就在 ISR 中进行任务切换。

configTICK_RATE_HZ 配置项定义每秒的滴答数(通常设为 1000,即 1ms 一次滴答)。

上下文切换

Basic concept

上下文是任务执行时使用的所有处理器资源(寄存器、堆栈等)的集合。

上下文切换就是:暂停当前任务时保存其上下文到栈中,切换到下一个任务时从栈中恢复其上下文。这样任务恢复执行时,"以为自己从未被打断过"。

Three triggers for context switch

  1. RTOS 滴答中断:处理就绪列表,判断是否抢占或时间片轮转
  2. 任务执行完毕:任务函数返回时自动切换
  3. 主动让出:调用 taskYIELD() 主动触发

PendSV mechanism

实际的上下文切换在 PendSV 中断服务函数中完成。PendSV 被设置为最低中断优先级,这样上下文切换不会影响其他关键 ISR。

触发方式:将 ICSR 寄存器的 bit28(PendSV 挂起位)置 1。

空闲任务

Basic concept

调度器启动时自动创建空闲任务,以最低优先级创建,确保至少有一个任务可运行。

空闲任务的三个作用:

作用 说明
释放被删任务的内存 任务调用 vTaskDelete 后,其资源在空闲任务中统一回收
CPU 空闲计数 统计 CPU 空闲率,辅助性能分析
低功耗模式 配合 tickless 模式,在空闲时进入低功耗状态

就绪列表

Ready list structure

就绪列表是 pxReadyTasksLists[x] 数组,其中 x 代表任务优先级(0 ~ configMAX_PRIORITIES-1)。

在 32 位硬件上,一个 32 位的位图变量标记哪些优先级对应的就绪列表中有任务:

就绪列表位图

多个相同优先级的任务连接在同一个就绪列表上:

同优先级就绪列表

调度器始终在所有就绪列表中选择最高优先级的任务来执行。

Core API Reference Table

Function Parameters Return Description
vTaskStartScheduler() void void 启动任务调度器
vTaskSuspend() TaskHandle_t void 挂起指定任务
vTaskResume() TaskHandle_t void 恢复被挂起的任务
taskYIELD() void void 主动请求任务切换

Common Issues & Pitfalls

  • 避免死循环占用 CPU:任务循环中必须包含阻塞操作(vTaskDelay、等待队列等),否则同优先级或低优先级任务无法运行。
  • 优先级反转:高优先级任务等待低优先级任务持有的资源时,可通过互斥信号量的优先级继承机制缓解。
  • 不要中断中调用阻塞 API:ISR 中调用会阻塞的 FreeRTOS API 可能导致系统崩溃,应使用带 FromISR 后缀的函数。