24.任务状态机.md 4.6 KB

任务状态机

判别规则(核心,唯一要记的)

  • 任务"在跑" = 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


每主题一页,复习时只翻本目录。