任务优先级管理
优先级设计的核心是分组预留 + 调度可预测:先分层、再预留空档,最后用量化指标验证。
核心原则
| 原则 | 说明 |
|---|---|
| 关键路径优先 | 影响系统核心功能的任务给最高优先级(紧急停机、安全检测) |
| 实时性分层 | 按响应时间分层:μs 级 > ms 级 > 秒级 |
| 资源依赖解耦 | 共享资源访问任务设互斥优先级区间,避免 I/O 任务互相阻塞 |
| 能耗优化 | 低功耗场景后台任务用最低优先级 + 休眠唤醒 |
优先级分组预留
把优先级空间划分逻辑组,每组预留 ≥4 个空闲级别用于细调。
| 组 | 区间 | 用途 |
|---|---|---|
| 紧急组 | 31–28 | 安全、停机 |
| 实时组 | 27–20 | 硬实时(传感器采样等) |
| 应用组 | 19–10 | 软实时业务、协议解析 |
| 后台组 | 9–0 | 日志、上报、统计 |
典型划分示例
#define PRI_EMERGENCY (configMAX_PRIORITIES-1) // 紧急事件(最高)
#define PRI_HARD_REALTIME (PRI_EMERGENCY-4) // 硬件实时(传感器采样)
#define PRI_SOFT_REALTIME (PRI_HARD_REALTIME-5) // 软件实时(协议解析)
#define PRI_NORMAL (PRI_SOFT_REALTIME-7) // 常规业务
#define PRI_BACKGROUND (1) // 后台任务(日志上传)高频决策
| 场景 | 策略 |
|---|---|
| 优先级不够用 | ① 合并同 QoS 任务到同一优先级 → ② 开时间片轮转 configUSE_TIME_SLICING → ③ 最后才改 configMAX_PRIORITIES |
| 防高优先级饿死低优先级 | 高优先级任务设最大连续执行时间;空闲任务跑看门狗检查;用 vTaskDelayUntil() 主动释放 CPU |
| 通信密集型系统 | 优先级带宽分配:ACK 响应 → PRIO_CRITICAL;TCP 重传 → PRIO_HIGH;数据解析 → PRIO_NORMAL;统计上报 → PRIO_LOW |
| 多个同优先级硬实时任务 | 执行时间严格可控 + vTaskDelayUntil() 释放 CPU;开时间片轮转;错开触发相位(一个 0ms、一个 2ms 启动);共享资源(如 I²C)互斥锁隔离或拆专用通道 |
| 动态添加任务 | 分组预留(每组 ≥4 空闲级别)+ 按业务属性(周期性/响应时限/安全性)归组 + 任务注册接口 + 优先级分配策略表 |
优先级反转案例(手表系统)
touch_scan_task(高)等待 sensor_polling_task(低)持有的 I²C 总线被阻塞,中优先级 display_refresh_task 持续运行,低优先级拿不到 CPU、无法释放总线 → 典型优先级反转。
解决:
- I²C 访问封装进支持优先级继承的互斥锁(FreeRTOS mutex):高优先级任务等待时,自动提升持锁任务优先级,让它快速执行完并释放。
- 后续把关键传感器访问任务提到硬实时区间,减少跨层资源依赖。
优先级反转/继承/天花板的理论见 死锁、饥饿与优先级反转
量化评估
| 维度 | 方法 | 标准 |
|---|---|---|
| 响应时间 | 逻辑分析仪/时间戳测「就绪 → 完成」耗时 | 对比周期/截止时间,如 5ms 周期任务最坏 ≤4ms |
| CPU 占用与抖动 | 空闲任务统计负载、测启动时间偏差 | 硬实时抖动 <10% 周期,负载 <70% |
| 阻塞与饥饿 | 监控 mutex 等待时长、低优先级任务是否长期无执行 | storage 类任务不超 5s 未处理队列 |
判定标准:所有硬实时任务 100% 满足截止时间 + 后台任务不被饿死 + 系统负载 <70%。看门狗频繁触发或日志积压 = 优先级配置失衡。