高优先级持续运行
高优先级任务进入循环执行且频繁占用CPU,不断被调度器选中执行。
饥饿现象是调度系统在缺乏公平性机制时产生的典型行为:高优先级任务长期占用CPU, 导致低优先级任务无法获得执行机会。本示例展示任务饥饿的产生原因及其对系统公平性的影响。
系统运行两个不同优先级任务:task_high(高优先级)和 task_low(低优先级), 高优先级任务持续占用CPU,导致低优先级任务无法获得调度。验证优先级调度中的饥饿现象。
任务饥饿现象的核心组成
任务饥饿(Starvation)是指在优先级调度系统中,高优先级任务长期占用CPU资源, 导致低优先级任务虽然处于就绪状态但无法获得执行机会的现象。 这不是系统错误,而是调度策略在缺乏公平补偿机制时的自然结果。
高优先级任务进入循环执行且频繁占用CPU,不断被调度器选中执行。
每次调度决策时,高优先级任务总是优先于低优先级任务被选中。
低优先级任务虽然处于就绪状态,但始终无法获得CPU执行窗口。
系统未引入时间片轮转(RR)或优先级老化(aging)等公平机制。
调度器的工作原理与饥饿产生原因
调度器根据优先级决策选择任务执行,在没有公平补偿机制的情况下, 高优先级任务会持续抢占CPU,导致低优先级任务饥饿。
队列组织:按优先级组织多个就绪队列
选择原则:优先选择高优先级队列中的任务
队列遍历:从高到低遍历优先级队列
任务插入:任务按优先级插入对应队列
决策依据:任务优先级数值
高优先级优先:数值越大,优先级越高
同优先级:采用FIFO或时间片轮转
决策时机:每次调度触发时重新决策
抢占条件:高优先级任务就绪时抢占低优先级任务
抢占时机:中断返回或任务让出CPU时
上下文保存:被抢占任务状态保存到任务栈
恢复执行:高优先级任务完成后恢复被抢占任务
策略启用:可选启用同优先级时间片轮转
时间片单位:以系统Tick为基本单位
轮转范围:仅在同优先级任务间轮转
饥饿缓解:无法解决跨优先级饥饿问题
任务饥饿现象产生的必要条件
任务饥饿不是随机发生的,而是在特定条件下必然出现的调度行为。 理解这些触发条件有助于识别和避免饥饿问题。
循环执行:任务进入无限循环且不主动让出CPU
频繁占用:任务执行时间短但频繁被调度
无阻塞操作:任务不调用延时或等待函数
持续就绪:任务始终处于可执行状态
纯优先级调度:仅基于优先级进行调度决策
无同优先级RR:同优先级任务间也无时间片限制
调度器行为:始终优先选择高优先级任务
缺乏平衡:没有机制强制低优先级任务执行
就绪状态:任务处于Ready队列但无法被调度
等待窗口:任务等待高优先级任务让出CPU
执行机会:执行机会极低或完全消失
响应延迟:任务响应时间远超预期
无RR机制:未启用时间片轮转调度
无Aging机制:未实现优先级老化补偿
无配额限制:高优先级任务无CPU时间配额
自然结果:饥饿是调度策略的自然结果
任务饥饿现象的完整执行路径
任务饥饿现象的完整实现
task_high 和 task_low 任务函数,展示优先级差异导致的饥饿现象
#include "hrtos.h"
sbit LED_HIGH = P1^0;
sbit LED_LOW = P1^1;
void task_high(void)
{
while(1)
{
LED_HIGH = ~LED_HIGH;
os_task_yield();
u16 i = 20000;
while(i--);
}
}
void task_low(void)
{
while(1)
{
LED_LOW = 1;
os_delay(10);
LED_LOW = 0;
os_delay(10);
}
}
hrtos_main 函数,创建高优先级和低优先级任务
void hrtos_main(void)
{
os_task_create((unsigned int)task_high, 1, 4, 5);
os_task_create((unsigned int)task_low, 2, 1, 5);
}
示例执行后的预期行为
使用本示例时需要关注的关键点
任务饥饿是调度策略在缺乏公平补偿机制时的自然结果,不是系统错误。 理解这一点有助于正确设计调度策略和任务优先级。
在设计任务优先级时,应避免高优先级任务持续占用CPU。 高优先级任务应执行时间短、频率低,或主动让出CPU。
工程中通常通过时间片轮转(RR)、优先级继承、优先级老化(aging)等机制缓解饥饿问题。 选择合适的方法取决于应用场景和实时性要求。
饥饿现象揭示了调度公平性与实时性之间的冲突。 实时性要求高优先级任务快速响应,而公平性要求低优先级任务获得执行机会。 需要根据应用需求在两者之间进行权衡。
深入学习的相关资源