RTOS的几种常见调度策略

RTOS(实时操作系统)的调度策略是决定哪个任务在何时获得CPU使用权的核心机制。理解这些策略,是进行嵌入式多任务开发的基础。

从裸机(前后台架构)开发过渡到RTOS开发,对于很多经验不足的工程师可能是一项艰难作。

但使用RTOS有许多优势,例如简化应用集成,支持任务抢占调度,当开发人员使用复杂的32位微控制器,且可以获取足够的Flash和RAM空间时,使用RTOS开始变得有意义。

本文给大家分享一下RTOS的几常见调度策略。

1、抢占式调度

抢占式调度是RTOS中最核心、最常见的策略,确保了系统的实时性和响应能力。

核心思想:每个任务都有一个固定的优先级。调度器会始终运行当前处于就绪态且优先级最高的任务。一旦一个更高优先级的任务变为就绪态(例如,它等待的中断发生了),它就会立即抢占当前正在运行的低优先级任务的CPU使用权。

大概流程:

比如:FreeRTOS通过配置和任务创建实现

cpp 复制代码
// 1. 在 FreeRTOSConfig.h 中确保抢占式调度开启
#define configUSE_PREEMPTION    1   // 1: 开启抢占式调度

// 2. 创建两个不同优先级的任务
void vHighPriorityTask(void *pvParameters)
{
    for (;;)
    {
        // 执行关键操作
        vTaskDelay(pdMS_TO_TICKS(100)); // 模拟任务阻塞
    }
}
void vLowPriorityTask(void *pvParameters)
{
    for (;;)
    {
        // 执行非关键操作
    }
}

void main()
{
    // 创建高优先级任务 (优先级为 2)
    xTaskCreate(vHighPriorityTask, "High", 256, NULL, 2, NULL);
    // 创建低优先级任务 (优先级为 1)
    xTaskCreate(vLowPriorityTask, "Low", 256, NULL, 1, NULL);
    vTaskStartScheduler(); // 启动调度器
}

FreeRTOS中每个任务的时间片长度是固定的,为一个时间节拍;而μC/OS-III中每个任务的时间片长度可变,可在任务创建时指定。

2、时间片轮询调度

这种策略主要用于处理多个相同优先级的任务,保证它们都能得到执行机会.

前后台系统实现通常基于轮询调度技术,它是一种很自然的软件编写方式,只需向超级循环中添加新代码,相当于增加了一个新的任务。

RTOS中的轮询调度策略,是允许多个任务可以分配同一个优先级别。调度程序基于时钟监控任务时间,任务处于相关优先级,按照先进先出的原则执行分配到的时间片,时间到了,即使当前任务还没有完成,任务也将CPU时间传递给下一个任务。在下一个分配到的时间段内,该任务将从它停止的位置继续执行。

常用的RTOS,如μC/OS-III(Cs/OS3)、FreeRTOS都支持时间片轮询算法。FreeRTOS中每个任务的时间片长度是固定的,为一个时间节拍;而μC/OS-III中每个任务的时间片长度可变,可在任务创建时指定。

比如:FreeRTOS通过配置和任务创建实现

cpp 复制代码
// 1. 在 FreeRTOSConfig.h 中确保时间片轮转开启
#define configUSE_TIME_SLICING    1  // 1: 开启时间片轮转
#define configTICK_RATE_HZ        1000 // 时钟节拍频率 1000Hz,即时间片为 1ms

// 2. 创建两个相同优先级的任务
void vTaskA(void *pvParameters)
{
    for (;;) 
    {
        // 执行任务A的工作
    }
}
void vTaskB(void *pvParameters)
{
    for (;;) 
    {
        // 执行任务B的工作
    }
}
void main() {
    // 创建两个优先级相同的任务 (假设优先级为 1)
    xTaskCreate(vTaskA, "TaskA", 256, NULL, 1, NULL);
    xTaskCreate(vTaskB, "TaskB", 256, NULL, 1, NULL);
    vTaskStartScheduler(); // 启动调度器
}

3、基于优先级的协同调度

这是一种非抢占式的调度策略,所有任务"商量着来"。

核心思想:一个任务会一直运行,直到它主动释放CPU。释放的方式通常是调用特定的让出函数(如taskYIELD()),或者使自己进入阻塞态(如等待信号量或调用vTaskDelay())

在RTOS中,协同调度是基于优先级的非抢占调度方法。任务按优先级排序,并且是事件驱动类型的,一旦正在运行的任务完成,或者任务主动调用OS服务放弃CPU,就绪运行的优先级最高的任务才可以获得CPU使用权。

比如:

cpp 复制代码
// 1. 在 FreeRTOSConfig.h 中关闭抢占式调度
#define configUSE_PREEMPTION    0   // 0: 关闭抢占式调度,即为协作式[reference:31][reference:32]

void vCooperativeTask(void *pvParameters) 
{
    for (;;) 
    {
        // 执行任务工作...

        // 主动让出CPU,让其他同优先级或低优先级任务运行
        taskYIELD(); 
    }
}

4、总结

RTOS对于嵌入式软件开发人员来说是一个强大的工具。RTOS应用中,每个任务都有单独的任务控制块,其中包含堆栈、优先级和ID等参数。每个任务都可以被看作是单独的应用程序。RTOS还提供了各种各样的同步和通信工具,如信号量、互斥信号量和消息队列,简化应用的开发。

但任务切换将消耗CPU时间,即使在32位处理器上,RTOS也会造成时间损失。任务切换比中断占用更多的时间。如果是一个很小的应用程序,但需要充分利用处理器资源,在这种情况下,需仔细考虑RTOS的可行性。

策略 实时性 公平性 复杂度 典型应用场景
抢占式调度 低(低优先级可能饥饿) 硬实时 任务,如电机控制、紧急中断响应
时间片轮转 同优先级任务的公平调度,如多通道数据采集
协作式调度 低功耗 设备、任务间耦合紧密的场景

每种调度算法都有其优缺点,了解RTOS常用的调度算法,可以帮助我们做出合适的选择。

相关推荐
圆奋奋3 小时前
FreeRTOS学习(十)- 最核心的内容:优先级抢占式调度 + 上下文切换
学习·freertos
hsjiasb3 天前
FreeRTOS学习(二十七)——任务栈与栈溢出检测
开发语言·stm32·学习·学习笔记·freertos
捷瑞电子工坊3 天前
FreeRTOS 空闲任务与阻塞延时
freertos·嵌入式实时操作系统·空闲任务·阻塞延时·vtaskdelay
hsjiasb3 天前
FreeRTOS学习(二十九)——低功耗Tickless Idle
学习·学习笔记·freertos
捷瑞电子工坊3 天前
FreeRTOS 临界段:为什么关中断?怎么用才安全?
嵌入式·freertos·实时操作系统·临界段·临界区
捷瑞电子工坊4 天前
FreeRTOS 就绪列表详解:任务调度的核心枢纽
freertos·任务调度·优先级·嵌入式实时操作系统·就绪列表
hsjiasb6 天前
FreeRTOS学习(二十六)——动态内存管理heap_1到heap_5
stm32·单片机·学习·学习笔记·freertos
hsjiasb7 天前
FreeRTOS学习(二十三)——消息缓冲区(Message Buffer)
stm32·单片机·嵌入式硬件·学习·freertos
圆奋奋10 天前
FreeRTOS学习(三)- 任务调度模块
学习·开源·freertos