H HRTOS 示例
Scheduling Behavior

饥饿现象

饥饿现象是调度系统在缺乏公平性机制时产生的典型行为:高优先级任务长期占用CPU, 导致低优先级任务无法获得执行机会。本示例展示任务饥饿的产生原因及其对系统公平性的影响。

示例目标

系统运行两个不同优先级任务:task_high(高优先级)和 task_low(低优先级), 高优先级任务持续占用CPU,导致低优先级任务无法获得调度。验证优先级调度中的饥饿现象。

核心API os_task_create
调度策略 优先级抢占
问题现象 任务饥饿
解决方案 RR / Aging

核心机制

  • 高优先级持续运行
  • Ready队列长期被覆盖
  • 低优先级无法调度
  • 调度公平性缺失
Mechanism Definition

机制定义

任务饥饿现象的核心组成

任务饥饿(Starvation)是指在优先级调度系统中,高优先级任务长期占用CPU资源, 导致低优先级任务虽然处于就绪状态但无法获得执行机会的现象。 这不是系统错误,而是调度策略在缺乏公平补偿机制时的自然结果。

核心公式: Starvation = 高优先级持续运行 + Ready队列长期被覆盖 + 低优先级无法调度

高优先级持续运行

高优先级任务进入循环执行且频繁占用CPU,不断被调度器选中执行。

Ready队列被覆盖

每次调度决策时,高优先级任务总是优先于低优先级任务被选中。

低优先级无法调度

低优先级任务虽然处于就绪状态,但始终无法获得CPU执行窗口。

缺乏公平补偿

系统未引入时间片轮转(RR)或优先级老化(aging)等公平机制。

Scheduler Model

调度器模型

调度器的工作原理与饥饿产生原因

调度器根据优先级决策选择任务执行,在没有公平补偿机制的情况下, 高优先级任务会持续抢占CPU,导致低优先级任务饥饿。

调度器组成: Scheduler = Ready队列选择 + 优先级决策 + 抢占机制 + 时间片策略(若启用)

Ready队列选择

队列组织:按优先级组织多个就绪队列

选择原则:优先选择高优先级队列中的任务

队列遍历:从高到低遍历优先级队列

任务插入:任务按优先级插入对应队列

优先级决策

决策依据:任务优先级数值

高优先级优先:数值越大,优先级越高

同优先级:采用FIFO或时间片轮转

决策时机:每次调度触发时重新决策

抢占机制

抢占条件:高优先级任务就绪时抢占低优先级任务

抢占时机:中断返回或任务让出CPU时

上下文保存:被抢占任务状态保存到任务栈

恢复执行:高优先级任务完成后恢复被抢占任务

时间片策略

策略启用:可选启用同优先级时间片轮转

时间片单位:以系统Tick为基本单位

轮转范围:仅在同优先级任务间轮转

饥饿缓解:无法解决跨优先级饥饿问题

Trigger Conditions

触发条件

任务饥饿现象产生的必要条件

任务饥饿不是随机发生的,而是在特定条件下必然出现的调度行为。 理解这些触发条件有助于识别和避免饥饿问题。

高优先级任务持续运行

循环执行:任务进入无限循环且不主动让出CPU

频繁占用:任务执行时间短但频繁被调度

无阻塞操作:任务不调用延时或等待函数

持续就绪:任务始终处于可执行状态

缺乏时间片轮转机制

纯优先级调度:仅基于优先级进行调度决策

无同优先级RR:同优先级任务间也无时间片限制

调度器行为:始终优先选择高优先级任务

缺乏平衡:没有机制强制低优先级任务执行

低优先级任务长期Ready

就绪状态:任务处于Ready队列但无法被调度

等待窗口:任务等待高优先级任务让出CPU

执行机会:执行机会极低或完全消失

响应延迟:任务响应时间远超预期

无公平调度补偿

无RR机制:未启用时间片轮转调度

无Aging机制:未实现优先级老化补偿

无配额限制:高优先级任务无CPU时间配额

自然结果:饥饿是调度策略的自然结果

Execution Flow

执行流程

任务饥饿现象的完整执行路径

1创建任务:hrtos_main 中创建 task_high(优先级4)和 task_low(优先级1),两个任务进入 Ready 状态
2高优先级占用CPU:调度器选择 task_high 进入 Running 状态,任务持续运行形成调度主导
3低优先级进入Ready:task_low 被唤醒并加入就绪队列,等待调度器分配CPU时间
4调度长期偏置:每次调度决策时,task_high 因高优先级始终被选中,Ready队列不断被抢占
5饥饿现象出现:task_low 长期处于 Ready 状态但无法获得执行机会,执行机会极低或消失
hrtos_main → os_task_create → 优先级差异 → 调度器选择 → 高优先级运行 → 低优先级Ready → 调度偏置 → 持续抢占 → 饥饿现象
Core Code

核心代码

任务饥饿现象的完整实现

任务函数实现

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);
}
Expected Result

运行结果

示例执行后的预期行为

LED 状态 LED_HIGH 频繁变化,LED_LOW 几乎不变化或变化极慢,直观展示饥饿现象
任务调度 task_high 持续占用CPU,task_low 长期处于 Ready 状态但无法获得执行机会
系统状态 调度器始终选择高优先级任务,低优先级任务响应时间极长
系统本质: 本示例的核心不是 LED,而是验证 HRTOS 中:高优先级任务长期占用CPU会导致低优先级任务饥饿, 揭示调度公平性与实时性之间的冲突。
Important Notes

注意事项

使用本示例时需要关注的关键点

饥饿不是错误

任务饥饿是调度策略在缺乏公平补偿机制时的自然结果,不是系统错误。 理解这一点有助于正确设计调度策略和任务优先级。

优先级设计原则

在设计任务优先级时,应避免高优先级任务持续占用CPU。 高优先级任务应执行时间短、频率低,或主动让出CPU。

缓解饥饿的方法

工程中通常通过时间片轮转(RR)、优先级继承、优先级老化(aging)等机制缓解饥饿问题。 选择合适的方法取决于应用场景和实时性要求。

公平性与实时性权衡

饥饿现象揭示了调度公平性与实时性之间的冲突。 实时性要求高优先级任务快速响应,而公平性要求低优先级任务获得执行机会。 需要根据应用需求在两者之间进行权衡。