4.2.1 任务状态机
2026/7/16大约 5 分钟内核组件内核任务管理状态机任务状态
4.2.1 任务状态机
📚 本节导读
学习时长: 约 20 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 任务控制块(TCB)基本概念
🎯 学习目标
- 理解 OneOS 中 7 种任务状态的含义
- 掌握任务状态之间的转换规则
- 能够通过状态位掩码判断任务所处的状态组合
一、任务状态定义
OneOS-Lite 定义了 7 种任务状态(外加 EMPTY 空状态),定义在 kernel/include/os_task.h 中:
#define OS_TASK_STATE_EMPTY 0x0000U /* 空状态(未使用) */
#define OS_TASK_STATE_INIT 0x0001U /* 初始化状态 */
#define OS_TASK_STATE_READY 0x0002U /* 就绪状态(等待调度) */
#define OS_TASK_STATE_RUNNING 0x0004U /* 运行状态(当前正在执行) */
#define OS_TASK_STATE_SLEEP 0x0008U /* 睡眠状态(延时等待) */
#define OS_TASK_STATE_BLOCK 0x0010U /* 阻塞状态(等待资源) */
#define OS_TASK_STATE_SUSPEND 0x0020U /* 挂起状态(手动暂停) */
#define OS_TASK_STATE_CLOSE 0x8000U /* 关闭状态(任务结束) */
#define OS_TASK_STATE_MASK 0xFFFFU /* 任务状态掩码 */各状态采用位掩码(bitmask)方式定义,这意味着一个任务可以同时处于多个状态的组合(例如:任务可以在 SLEEP 状态的同时被 SUSPEND)。
各状态详解
| 状态 | 掩码 | 描述 |
|---|---|---|
| EMPTY | 0x0000 | 空状态,TCB 尚未被使用 |
| INIT | 0x0001 | 初始化状态,任务已创建但尚未启动(os_task_create() 调用后) |
| READY | 0x0002 | 就绪状态,任务已准备好运行,等待调度器分配 CPU |
| RUNNING | 0x0004 | 运行状态,任务正在 CPU 上执行(同一时刻只有一个任务处于此状态) |
| SLEEP | 0x0008 | 睡眠状态,任务因延时调用(os_task_tsleep/os_task_msleep)而主动睡眠 |
| BLOCK | 0x0010 | 阻塞状态,任务因等待某个 IPC 资源(信号量、互斥锁、消息队列等)而被阻塞 |
| SUSPEND | 0x0020 | 挂起状态,任务被手动挂起(os_task_suspend()),可与 SLEEP/BLOCK 叠加 |
| CLOSE | 0x8000 | 关闭状态,任务即将被销毁,等待资源回收 |
二、任务状态转换图
下面是完整的任务状态转换图(ASCII 艺术图):
os_task_create()
│
▼
┌──────────────────┐
│ INIT │
│ (0x0001) │
└───────┬──────────┘
│ os_task_startup()
▼
┌──────────────────────────────────────────┐
│ READY │
│ (0x0002) │
└────┬──────────┬──────────┬───────────────┘
│ │ │
os_task_ │ 调度器选中│ │ os_task_suspend()
resume() │ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────┐ ┌──────────────────┐
│ SUSPEND │ │ RUNNING │ │ SUSPEND + READY │
│ (0x0020) │ │ (0x0004) │ │ (0x0022) ←─── 被恢复
└──────┬──────┘ └─┬──┬──┬──┘ └──────────────────┘
│ │ │ │
│ 被抢占 │ │ └── os_task_tsleep/msleep()
│ 或时间片到│ │
▼ │ ▼
┌─────────────┐ │ ┌──────────────────┐
│ SUSPEND + │ │ │ SLEEP │
│ READY │◄─────┘ │ (0x0008) │
│ (0x0022) │ └────────┬─────────┘
└─────────────┘ │ 延时到期
▼
┌──────────────┐
│ READY │
│ (0x0002) │
└──────────────┘
等待 IPC 资源(信号量、互斥锁等):
RUNNING ──os_sem_wait()等──► BLOCK (0x0010)
BLOCK ──资源可用──────────► READY (0x0002)
任务销毁:
RUNNING ──os_task_destroy()──► CLOSE (0x8000) ──► 资源回收 ──► EMPTY
挂起叠加(SUSPEND 可与 SLEEP/BLOCK 组合):
SLEEP ──os_task_suspend()──► SLEEP + SUSPEND (0x0028)
BLOCK ──os_task_suspend()──► BLOCK + SUSPEND (0x0030)三、状态转换规则详解
3.1 INIT → READY
- 触发条件:调用
os_task_startup() - 说明:任务创建后处于 INIT 状态,必须调用
os_task_startup()将其加入就绪队列才能被调度执行
3.2 READY → RUNNING
- 触发条件:调度器选中该任务(它是当前最高优先级的就绪任务)
- 说明:就绪任务被调度器选中后获得 CPU 使用权,状态变为 RUNNING
3.3 RUNNING → READY
- 触发条件:
- 被更高优先级任务抢占
- 时间片用完(同优先级轮转调度)
- 主动调用
os_task_yield()让出 CPU
- 说明:任务失去 CPU 使用权但仍在就绪状态,等待下次调度
3.4 RUNNING → SLEEP
- 触发条件:调用
os_task_tsleep(tick)或os_task_msleep(ms) - 说明:任务主动进入睡眠状态,内核将其从就绪队列移除,加入延时队列。延时到期后自动回到 READY 状态
3.5 RUNNING → BLOCK
- 触发条件:任务尝试获取不可用的 IPC 资源(如信号量 count=0、互斥锁被占用等)
- 说明:任务从就绪队列移除,加入对应 IPC 对象的阻塞等待队列。当资源可用时自动回到 READY 状态
3.6 RUNNING/READY/SLEEP/BLOCK → SUSPEND
- 触发条件:其他任务(或自身)调用
os_task_suspend() - 说明:
- 如果任务在 READY 状态:从就绪队列移除,状态变为
SUSPEND - 如果任务在 SLEEP 状态:保留 SLEEP 状态,叠加
SUSPEND(状态变为SLEEP | SUSPEND) - 如果任务在 BLOCK 状态:保留 BLOCK 状态,叠加
SUSPEND(状态变为BLOCK | SUSPEND) - 如果任务在 RUNNING 状态(自己挂起自己):立即触发调度
- 如果任务在 READY 状态:从就绪队列移除,状态变为
3.7 SUSPEND → READY
- 触发条件:调用
os_task_resume() - 说明:
- 如果任务仅处于
SUSPEND状态:清除 SUSPEND,转为 READY 状态 - 如果任务处于
SLEEP | SUSPEND状态:仅清除 SUSPEND,保留 SLEEP(等延时到期后自动回到 READY) - 如果任务处于
BLOCK | SUSPEND状态:仅清除 SUSPEND,保留 BLOCK(等资源可用后自动回到 READY)
- 如果任务仅处于
3.8 RUNNING → CLOSE
- 触发条件:调用
os_task_destroy()或任务入口函数返回 - 说明:任务进入关闭状态,内核的回收任务(recycle-task)会负责执行清理回调和释放资源
四、状态掩码的组合使用
由于状态采用位掩码定义,可以使用位运算来判断任务的状态组合:
#include <os_task.h>
uint16_t status;
os_task_get_state(tid, &status);
/* 判断任务是否处于就绪状态 */
if (status & OS_TASK_STATE_READY) {
/* 任务就绪 */
}
/* 判断任务是否处于挂起状态(可能同时处于其他状态) */
if (status & OS_TASK_STATE_SUSPEND) {
/* 任务被挂起 */
}
/* 判断任务是否处于睡眠且挂起状态 */
if ((status & (OS_TASK_STATE_SLEEP | OS_TASK_STATE_SUSPEND)) ==
(OS_TASK_STATE_SLEEP | OS_TASK_STATE_SUSPEND)) {
/* 任务同时处于睡眠和挂起状态 */
}注意:
os_task_get_state()内部对 RUNNING 状态做了特殊处理——如果查询的是当前正在运行的任务,返回的状态中会包含OS_TASK_STATE_RUNNING,而不是OS_TASK_STATE_READY。这是因为 RUNNING 任务的实际内部状态位是 READY,但为了方便外部查询,API 做了转换。
📝 本节小结
OneOS 任务状态机采用位掩码设计,定义了 7 种状态(INIT、READY、RUNNING、SLEEP、BLOCK、SUSPEND、CLOSE)。状态之间通过特定的 API 调用触发转换,SUSPEND 状态可以与其他状态叠加。理解任务状态机是掌握任务管理的基础,后续各节将详细介绍每个状态转换的具体 API 用法。