在某些情况下,我们可能希望指定的任务能够优先运行、甚至是打断其它任务的执行,因为该任务要完成的工作更加紧急或重要。为解决此问题,可以为该任务指定更高的优先级。

什么是优先级调度

我们已经知道,很多RTOS会采用优先级队列来组织所有已经就绪的任务。同样地,RT-Thread也不例外:

RT-Thread内核支持基于优先级的抢占式调度

  • 每个任务在创建时会指定一个优先级(0~255,数字越小,优先级越高)。
  • 内核总是选取当前就绪任务中优先级最高的任务来运行。
  • 当有更高优先级的任务进入就绪态,调度器立即中断当前低优先级任务,切换到高优先级任务。

可以看到,高优先级的任务总是有优先运行的机会,它会打断低优先级任务的运行,抢占执行机会。--- 抢占式调度

示例代码

如下图所示,演示了高优先任务t2抢占低优先级任务t1运行机会的情况。当t2使用for()进行延时时,t1没有任何运行机会;而只有当t2使用rt_thread_mdelay()进行延迟时,即主要放弃CPU暂停运行,t1才有运行的机会。

#include <rtthread.h>
#include "base.h"

void task1_entry(void *param) {
    RT_UNUSED(param);

    while (1) {
        rt_kprintf("Task 1 is running\n");
        // 忙等待模拟工作
        //for (int i = 0; i < 100000; i++);
        rt_thread_mdelay(200);
    }
}

void task2_entry(void *param) {
    RT_UNUSED(param);

    while (1) {
        rt_kprintf("Task 2 is running\n");
        for (int i = 0; i < 100000; i++);
    }
}

int main(void) {
    hardware_init();

    //  0 -- 
    rt_thread_t t1 = rt_thread_create(
        "t1",
        task1_entry,
        RT_NULL,
        1024,
        10,     // 相同优先级
        20       // 时间片为5个tick, 20*1ms = 20ms
    );

    rt_thread_t t2 = rt_thread_create(
        "t2",
        task2_entry,
        RT_NULL,
        1024,
        20,     // 相同优先级
        40          // 40*1ms = 40ms
    );

    if (t1) rt_thread_startup(t1);
    if (t2) rt_thread_startup(t2);

    return 0;
}

运行过程的分析示意图如下:

注意事项

由于引入了优先级,在为任务配置优先级时需要注意以下事项。

  • 优先级设计要合理:不合理的优先级设置可能导致低优先级任务“饿死”。
  • 避免高优先级任务一直占用 CPU:要合理加入rt_thread_mdelay()或rt_thread_yield()等接口
  • 不要所有任务设为同一个优先级,否则调度结果受时间片影响,无法体现优先级机制。

课程推荐

 作者介绍 李述铜,嵌入式系统与底层架构领域讲师,专注于操作系统、CPU 架构、RTOS 内核与系统软件实现原理的教学与研究。 出版作品《从0手写x86计算机操作系统》,主讲课程包括:《从0手写嵌入式操作系统》《从0手写TCP/IP协议栈》《从0手写FAT32文件系统》等。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐