4.2.4 任务优先级
4.2.4 任务优先级
📚 本节导读
学习时长: 约 15 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 任务调度机制、优先级抢占概念
🎯 学习目标
- 理解优先级的取值范围和配置方式
- 掌握
os_task_set_priority()和os_task_get_priority()的用法 - 理解互斥锁场景下的优先级继承机制
- 了解系统任务的优先级安排
- 掌握优先级分配的最佳实践
一、优先级范围与配置
1.1 优先级范围
在 OneOS 中,优先级数值越小,优先级越高。0 是最高优先级,OS_TASK_PRIORITY_MAX - 1 是最低优先级。
1.2 配置方式
优先级最大值通过 Kconfig 配置,位于 kernel/Kconfig 的 Task 菜单中:
choice
prompt "The max level value of priority of task"
default OS_TASK_PRIORITY_32
config OS_TASK_PRIORITY_8 → bool "8"
config OS_TASK_PRIORITY_16 → bool "16"
config OS_TASK_PRIORITY_32 → bool "32" ← 默认
config OS_TASK_PRIORITY_64 → bool "64"
config OS_TASK_PRIORITY_128 → bool "128"
config OS_TASK_PRIORITY_256 → bool "256"
endchoice| 配置选项 | 优先级范围 | 适用场景 |
|---|---|---|
| 8 | 0 ~ 7 | 极简系统,任务数量极少 |
| 16 | 0 ~ 15 | 简单嵌入式系统 |
| 32 | 0 ~ 31 | 默认配置,适合大多数场景 |
| 64 | 0 ~ 63 | 中等复杂度系统 |
| 128 | 0 ~ 127 | 复杂系统,任务较多 |
| 256 | 0 ~ 255 | 大型系统,任务数量多且需要精细优先 |
注意:
OS_TASK_PRIORITY_MAX不能超过 256,调度器代码中对此有编译时检查。
1.3 调度器位图与优先级
当 OS_TASK_PRIORITY_MAX ≤ 32 时,调度器使用单个 uint32_t 位图;当 OS_TASK_PRIORITY_MAX > 32 时,使用两级位图(组位图 + 组内位图)。两者都保证了 O(1) 的最高优先级查找时间。
二、os_task_set_priority() —— 设置优先级
2.1 函数签名
os_err_t os_task_set_priority(os_task_id tid, uint8_t new_priority);2.2 参数说明
| 参数 | 说明 |
|---|---|
tid | 目标任务的任务 ID |
new_priority | 新的优先级值,必须 < OS_TASK_PRIORITY_MAX |
2.3 内部行为
根据任务当前状态,优先级修改的处理方式不同:
| 任务当前状态 | 处理方式 |
|---|---|
| READY | 从就绪队列移除 → 更新优先级 → 重新加入就绪队列 → 触发调度 |
| BLOCK(优先级唤醒) | 从阻塞队列移除 → 更新优先级 → 按新优先级重新插入阻塞队列 |
| BLOCK(FIFO 唤醒) | 仅更新优先级,不调整阻塞队列位置 |
| 其他状态 | 直接更新 current_priority 字段 |
如果任务持有互斥锁,则只更新 backup_priority(备用优先级),不修改 current_priority。这是因为互斥锁的优先级继承机制需要保持提升后的优先级。
2.4 使用示例
/* 修改其他任务的优先级 */
os_task_id tid = os_task_get_id("worker_task");
os_task_set_priority(tid, 3); /* 提升到优先级 3 */
/* 修改自己的优先级 */
os_task_set_priority(os_get_current_task(), 10);三、os_task_get_priority() —— 获取优先级
3.1 函数签名
os_err_t os_task_get_priority(os_task_id tid, uint8_t *priority);3.2 使用示例
uint8_t prio;
os_task_get_priority(tid, &prio);
os_kprintf("Task priority: %u\r\n", prio);注意:返回的是
current_priority(当前优先级),如果任务持有互斥锁且发生了优先级继承,返回的可能是继承后的优先级,而不是原始优先级。
四、优先级继承机制
4.1 问题场景
优先级反转是 RTOS 中的经典问题。假设有三个任务:
- 任务 H(高优先级,优先级 1)
- 任务 M(中优先级,优先级 5)
- 任务 L(低优先级,优先级 10)
场景:优先级反转
────────────────────────────────────────────►
任务 L 获取互斥锁 ──┬──────────┬── 释放锁
│ │
任务 M └──────────┤ (中优先级任务抢占,导致 L 无法释放锁)
│
任务 H ──────┼── 尝试获取锁,被阻塞
│
┌───────────────┘
▼
任务 H 被 M(无关任务)间接阻塞!4.2 OneOS 的优先级继承
OneOS 的互斥锁实现了优先级继承机制来解决优先级反转问题:
- 当高优先级任务 H 尝试获取已被低优先级任务 L 持有的互斥锁时
- L 的
current_priority被临时提升到 H 的优先级(即优先级 1) backup_priority保存 L 的原始优先级(即优先级 10)- 当 L 释放互斥锁后,优先级恢复为
backup_priority
优先级继承的效果:
────────────────────────────────────────────►
任务 L 获取锁 ──┬── 优先级提升到 1 ──┬── 释放锁,恢复优先级 10
│ │
任务 H └── 尝试获取锁,L 被提升 └── 获取锁成功
任务 M 无法抢占 L(因为 L 的优先级已经是 1)4.3 优先级继承对 os_task_set_priority() 的影响
当任务持有互斥锁时,调用 os_task_set_priority() 只会更新 backup_priority,不会改变 current_priority。这样既保证了优先级继承机制的正常工作,也允许用户"预定"锁释放后的目标优先级。
/* 任务 L 持有互斥锁,且被提升了优先级 */
os_task_set_priority(tid_L, 12); /* 只更新 backup_priority */
/* 当 L 释放锁后,优先级自动恢复为 12,而不是原始的 10 */五、系统任务优先级
OneOS 内核自带以下系统任务,它们的优先级安排如下:
| 系统任务 | 名称 | 默认优先级 | 说明 |
|---|---|---|---|
| 空闲任务(idle) | "idle" | 最低(OS_TASK_PRIORITY_MAX - 1) | 当没有其他任务就绪时运行,通常执行低功耗相关操作 |
| 回收任务(recycle) | "recycle" | 0(最高) | 负责任务销毁后的资源回收(清理回调、释放内存) |
| 系统任务(sys) | 系统工作队列任务 | 0(最高,可配置) | 系统工作队列任务,处理延迟工作项 |
注意:回收任务优先级为 0(最高),确保被销毁任务的资源能尽快被回收。用户任务不应使用优先级 0,以免干扰系统任务的正常运行。
六、优先级分配最佳实践
6.1 分配原则
| 原则 | 说明 |
|---|---|
| 实时性优先 | 对时间要求严格的任务赋予更高优先级 |
| 关键路径优先 | 系统关键功能(如安全检测、通信协议)赋予高优先级 |
| 短任务优先 | 执行时间短、不阻塞的任务可赋予较高优先级 |
| 避免优先级 0 | 保留给系统任务使用 |
| 分层设计 | 将任务按功能分层,每层分配一个优先级段 |
6.2 推荐优先级分配示例(32 级优先级)
优先级 0: 系统任务(recycle、sys)
优先级 1~3: 实时控制任务(传感器采样、电机控制)
优先级 4~7: 通信协议处理(网络协议栈、CAN 通信)
优先级 8~15: 业务逻辑任务(数据处理、算法计算)
优先级 16~25: 后台任务(日志、监控、状态上报)
优先级 26~30: 低优先级任务(LED 指示、按键扫描)
优先级 31: 空闲任务(idle)6.3 注意事项
- 不要频繁修改优先级:动态优先级修改会触发调度,影响系统性能
- 避免优先级竞争:不要创建过多高优先级任务,防止低优先级任务饥饿
- 互斥锁搭配优先级继承:使用互斥锁保护共享资源时,优先级继承可以避免反转问题
- 中断优先级独立:任务的优先级和中断的优先级是两个独立的概念,互不影响
📝 本节小结
OneOS 的优先级范围为 0 ~ OS_TASK_PRIORITY_MAX - 1,数值越小优先级越高。优先级最大值可通过 Kconfig 配置(8/16/32/64/128/256)。os_task_set_priority() 可动态修改任务优先级,对于持有互斥锁的任务,修改仅影响备用优先级。互斥锁的优先级继承机制可有效解决优先级反转问题,确保系统实时性。系统任务占用最高优先级(0),用户任务应避开此优先级。