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常用的调度算法,可以帮助我们做出合适的选择。

相关推荐
长江后浪博客5 天前
ESP32-SOLO-1 在 ESP-IDF v5.5 下启动不断重启问题分析与解决
单片机·嵌入式硬件·嵌入式·esp32·freertos·esp-idf
WWJA王文举7 天前
FreeRTOS动态创建任务和静态创建任务详解:xTaskCreate与xTaskCreateStatic区别
操作系统·freertos·嵌入式开发
离凌寒10 天前
一、关于rtthread nano使用上的细节总结
freertos
桃蹊、10 天前
串口/网络透传实战:FreeRTOS 多任务架构与连接池设计
stm32·物联网·wifi·freertos
虎王物联10 天前
ESP32 FreeRTOS多任务优先级翻转与互斥量保护实战
物联网·嵌入式·esp32·freertos
桃蹊、10 天前
FreeRTOS(六)之队列:任务间通信的基石
freertos·队列
桃蹊、11 天前
FreeRTOS(二)之堆和栈:内存基础入门
freertos·内存管理··
桃蹊、11 天前
FreeRTOS(四)之任务管理(上):创建、删除与任务参数
freertos·任务·task·创建任务
论迹复利13 天前
PendSV与RISC-V trap——上下文切换的两种设计哲学
内核·freertos·risc-v
捷瑞电子工坊16 天前
FreeRTOS中断管理:从原理到实践(标准库版)
嵌入式·freertos·实时操作系统·任务通知·临界区·中断管理·二值信号量