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

相关推荐
zhangzhangkeji3 天前
FreeRTos笔记(12c):从事件链表里删除节点 xTaskRemoveFromEventList、
freertos
La Pulga3 天前
【FreeRTOS源码学习笔记】任务延时列表
笔记·mcu·学习·嵌入式·freertos·实时操作系统
橘色的喵3 天前
coact:让嵌入式事件处理更可控
freertos·rt-thread·事件驱动·coact
人邮异步社区4 天前
学习FreeRTOS推荐哪本书?
freertos·rtos·嵌入式固件工程师
La Pulga7 天前
【FreeRTOS源码学习笔记】空闲任务与阻塞延时
笔记·mcu·学习·嵌入式·freertos·实时操作系统
La Pulga7 天前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
La Pulga9 天前
【FreeRTOS源码学习笔记】链表的实现
数据结构·笔记·stm32·mcu·链表·嵌入式·freertos
La Pulga10 天前
【FreeRTOS源码学习笔记】任务创建
笔记·stm32·mcu·学习·嵌入式·freertos·实时操作系统
天吾cc15 天前
FreeRTOS 事件标志组
freertos
编码追梦人16 天前
基于 ESP32-S3 的便携式多参数环境监护仪设计:从硬件选型到 FreeRTOS 多任务落地
数据库·单片机·嵌入式硬件·mongodb·esp32·freertos·低功耗设计