## 任务状态机 ## 判别规则(核心,唯一要记的) - 任务"在跑" = **Running**;"排队等 CPU" = **Ready**;"主动等事件/延时" = **Blocked**(自动恢复、有超时);"被外部挂起" = **Suspended**(手动恢复、无超时) - 转换:**抢占/时间片 ↔ Running↔Ready;阻塞 API → Running→Blocked;vTaskSuspend/vTaskResume ↔ Suspended** 一句话:**"在跑是 Running,排队是 Ready,等闹钟是 Blocked,等别人叫是 Suspended。"** ## 抽象描述(一句话本质) 任务任何时候处于四种状态之一。核心判别:"这个任务现在为什么没在跑?"——排队等 CPU = Ready,自己等事件/延时 = Blocked(自动醒),被外部挂起 = Suspended(手动醒),在跑 = Running。 ## 状态转换表 | 从 → 到 | 触发 | | ------------------- | --------------------------------------------------- | | Running → Ready | 时间片用完(tick 到点) / 被高优先级抢占 | | Running → Blocked | 调阻塞 API(vTaskDelay / 等信号量 / 队列 / 事件组) | | Ready → Running | 调度器选中它 | | Running → Suspended | vTaskSuspend 挂起 | | Suspended → Ready | vTaskResume 恢复 | | Ready → Suspended | 不能直接(先 Running 或 Blocked 再挂起) | ## 正反例(建立直觉) - **正例1**:正在执行代码 = Running - **正例2**:调 `vTaskDelay(100)` 后 = Blocked(主动等延时) - **正例3**:被高优先级任务抢占后 = Ready(排队等 CPU) - **正例4**:执行 `vTaskSuspend(NULL)` 后 = Suspended - **反例1**:以为延时是 Suspended → 错,vTaskDelay 是 Blocked - **反例2**:以为 Running 会一直跑 → 会被更高优先级抢占回 Ready ## 易混对比 | | Blocked | Suspended | | -------- | -------------------------------- | -------------------- | | 原因 | 主动等待事件(延时/信号量/队列) | 被外部挂起 | | 怎么恢复 | 事件来了**自动**回 Ready | **必须 vTaskResume** | | 有超时吗 | 有(可设超时上限) | 无 | ## 变体验证(3 题,全过=学会) 1. 陷阱题:任务等一个**永不发生**的事件 → **永久 Blocked,永远轮不到执行**(死等/饥饿,RTOS 经典 bug 场景) 2. 陷阱题:阻塞事件到达 → **先回 Ready,再等调度器选**,不直接 Running(不能插队,保证调度器统一决策) 3. 同优先级两个任务 → **时间片轮转**:tick 到点,Running 任务用完时间片回 Ready 队尾,下一个 Ready 变 Running ## 口述要点(面试怎么讲) - **结论先行**:四种状态 + 一个核心问题"为什么没在跑" - **为什么事件到达先回 Ready 不直接 Running**:先进就绪队列让调度器统一决策,保证"正在运行的永远是最高优先级就绪任务"这条核心不变量不被绕过。直接 Running 会破坏抢占一致性 - **vTaskDelay vs vTaskDelayUntil**:vTaskDelay = **相对延时**(从调用起算,总周期 = 函数体 + 延时,如函数体 200ms + 延时 500ms → 周期约 700ms);vTaskDelayUntil = **绝对延时**(按固定周期醒来,周期固定 500ms)。**周期固定/硬实时周期任务 → DelayUntil**(前提:函数体时间 < 周期) - **时间片轮转**:不是"任务执行完成"才轮换,是**时间片用完(tick 到点)就轮换**,任务没做完也让位,下次接着跑 - **易错点**:延时是 Blocked 不是 Suspended;事件到达不直接 Running;轮换靠 tick 不靠任务完成 ## 关系网络 | 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 | | -------------- | ------------------------------------------------------- | ------------------------------ | | 抢占 vs 时间片 | Running↔Ready 的两条路径:高优先级抢占 / 同优先级时间片 | 以为时间片只在"任务完成后"发生 | | 信号量/队列 | Blocked 的进入/唤醒全靠它们 | 以为 Blocked 只能靠延时 | | 临界区 | 关中断期间调度不运行 | 以为临界区里任务还会被切走 | | 任务通知 | 最轻量的唤醒机制 | 以为唤醒必须用队列 | ## 学习日期 2026-08-03 --- _每主题一页,复习时只翻本目录。_