非抢占式调度和时间片轮转调度的区别是什么?

非抢占式调度(也叫协作式调度)和时间片轮转调度是 RTOS 中两种不同的任务调度逻辑,核心区别在于 CPU 控制权的切换方式适用场景实时性表现,具体对比分析如下:

一、核心定义与切换机制

1. 非抢占式调度(协作式调度)

  • 核心规则任务主动释放 CPU 控制权,内核才会切换到下一个就绪任务。
    任务一旦获得 CPU,会一直运行到主动放弃执行权(比如调用 taskYIELD()vTaskDelay(),或等待信号量/队列),内核不会强行打断它。
    任务的执行顺序由就绪队列的优先级排序决定,但高优先级任务无法抢占正在运行的低优先级任务——必须等低优先级任务主动释放 CPU,高优先级任务才能执行。
  • 切换触发条件
    1. 当前任务主动调用 taskYIELD() 放弃 CPU;
    2. 当前任务进入阻塞态(如延时、等待事件);
    3. 当前任务运行结束。

2. 时间片轮转调度

  • 核心规则内核强制剥夺 CPU 控制权,同优先级任务按固定时间片轮流执行。
    该调度仅对同优先级的就绪任务生效,内核会为每个任务分配一个固定时长的时间片(比如 10ms)。任务运行满一个时间片后,内核会主动触发上下文切换,将 CPU 切换给下一个同优先级的就绪任务;如果任务在时间片内主动释放 CPU(如延时、等待事件),则立即切换,剩余时间片作废。
  • 切换触发条件
    1. 当前任务运行时间达到时间片长度;
    2. 当前任务主动进入阻塞态或放弃 CPU;
    3. 有更高优先级的任务就绪(触发抢占式调度,时间片轮转被打断)。

二、核心区别对比表

对比维度 非抢占式调度(协作式) 时间片轮转调度
CPU 控制权切换 任务主动释放,内核不强制剥夺 内核强制剥夺 + 任务主动释放
优先级作用 高优先级任务需等待低优先级任务释放 CPU 仅对同优先级任务生效;高优先级任务可直接抢占
依赖的调度基础 独立调度方式,无依赖 依赖抢占式调度,必须开启抢占才能生效
实时性 差:低优先级任务可能“饿死”高优先级任务 中等:同优先级任务公平执行,高优先级可抢占
系统开销 极低:几乎无上下文切换的额外开销 中等:时间片到点强制切换,有上下文切换开销
编程要求 高:开发者必须确保任务主动释放 CPU 中:无需手动控制,内核自动分配时间片

三、典型应用场景与示例

1. 非抢占式调度的适用场景

适合任务逻辑简单、实时性要求极低的系统,比如小家电控制(风扇档位调节、台灯亮度控制)、单一功能传感器采集。
反面案例:如果用在工业控制场景,低优先级任务如果写了死循环(不主动释放 CPU),高优先级的紧急任务(如故障报警)会完全无法执行,导致系统瘫痪。

代码示例(非抢占式)

void LowPriorityTask(void *param) {
    while(1) {
        // 死循环,不主动释放 CPU
        for(int i=0; i<1000000; i++);
        // 若没有这行,高优先级任务永远无法执行
        taskYIELD(); // 主动放弃 CPU,切换到高优先级任务
    }
}

void HighPriorityTask(void *param) {
    while(1) {
        printf("高优先级任务执行\n");
        vTaskDelay(1000);
    }
}

运行结果:如果 LowPriorityTask 不调用 taskYIELD()HighPriorityTask 永远无法执行。

2. 时间片轮转调度的适用场景

适合多个同优先级任务需要公平并发执行的软实时场景,比如智能手表的“心率采集+通知推送+蓝牙数据传输”(三个任务优先级相同)。
关键特性:如果有更高优先级的任务就绪,会立即打断时间片轮转,优先执行高优先级任务;高优先级任务执行完毕后,再回到同优先级任务的时间片轮转。

代码示例(时间片轮转)

// 两个同优先级任务(优先级 1)
void TaskA(void *param) {
    while(1) {
        printf("任务 A 执行中\n");
        // 运行满时间片后,内核强制切换到 TaskB
    }
}

void TaskB(void *param) {
    while(1) {
        printf("任务 B 执行中\n");
        // 运行满时间片后,内核强制切换到 TaskA
    }
}

// 高优先级任务(优先级 2)
void HighTask(void *param) {
    while(1) {
        printf("高优先级任务抢占执行\n");
        vTaskDelay(2000);
    }
}

运行结果

  1. 正常情况下,TaskATaskB 按时间片轮流执行;
  2. HighTask 延时结束进入就绪态,会立即抢占 CPU,执行完毕后延时释放 CPU;
  3. 系统回到 TaskATaskB 的时间片轮转。
posted @ 2026-01-07 10:44  布衣开发者  阅读(15)  评论(0)    收藏  举报