RT-Thread 多任务调度详解

📊 调度器架构

RT-Thread 采用基于优先级的抢占式调度,支持时间片轮转

1. 任务状态

// 任务状态定义
RT_THREAD_INIT           // 初始状态
RT_THREAD_READY          // 就绪状态
RT_THREAD_RUNNING        // 运行状态
RT_THREAD_SUSPEND        // 挂起状态
RT_THREAD_CLOSE          // 关闭状态

2. 优先级管理

  • 优先级范围:0-255(0最高,255最低)
  • 系统优先级:0-31(系统线程)
  • 用户优先级:32-255(用户线程)
  • 相同优先级:支持时间片轮转调度

🔄 调度策略

抢占式调度

// 高优先级任务抢占低优先级任务
void high_priority_task(void* param)
{
    while(1) {
        rt_kprintf("High priority task running\n");
        rt_thread_mdelay(1000);
    }
}

void low_priority_task(void* param)
{
    while(1) {
        rt_kprintf("Low priority task running\n");
        rt_thread_mdelay(1000);
    }
}

// 创建任务(优先级不同)
rt_thread_create("high", high_priority_task, NULL, 512, 10, 10);
rt_thread_create("low", low_priority_task, NULL, 512, 20, 10);

时间片轮转

// 相同优先级任务使用时间片
static void task1_entry(void* parameter)
{
    while(1) {
        rt_kprintf("Task1 running\n");
        rt_thread_delay(5);  // 主动让出CPU
    }
}

static void task2_entry(void* parameter)
{
    while(1) {
        rt_kprintf("Task2 running\n");
        rt_thread_delay(5);
    }
}

// 创建相同优先级任务,设置时间片
rt_thread_t task1 = rt_thread_create("task1", task1_entry, NULL, 
                                     512, 10, 10);  // 优先级10,时间片10 ticks
rt_thread_t task2 = rt_thread_create("task2", task2_entry, NULL,
                                     512, 10, 10);  // 优先级10,时间片10 ticks

⚙️ 调度相关API

任务控制

// 创建线程
rt_thread_t rt_thread_create(const char* name,
                            void (*entry)(void* parameter),
                            void* parameter,
                            rt_uint32_t stack_size,
                            rt_uint8_t priority,
                            rt_uint32_t tick);

// 启动线程
rt_err_t rt_thread_startup(rt_thread_t thread);

// 删除线程
rt_err_t rt_thread_delete(rt_thread_t thread);

// 挂起线程
rt_err_t rt_thread_suspend(rt_thread_t thread);

// 恢复线程
rt_err_t rt_thread_resume(rt_thread_t thread);

// 让出CPU
rt_err_t rt_thread_yield(void);

延时函数

// 系统延时(基于系统节拍)
rt_err_t rt_thread_delay(rt_tick_t tick);      // 相对延时
rt_err_t rt_thread_sleep(rt_tick_t tick);      // 同delay
rt_err_t rt_thread_mdelay(rt_int32_t ms);      // 毫秒延时

// 绝对时间延时
rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick);

📈 调度器工作流程

调度触发时机

  1. 主动触发

    rt_thread_yield();      // 主动让出CPU
    rt_thread_delay();      // 延时等待
    rt_thread_suspend();    // 挂起自己
    
  2. 被动触发

    • 中断处理完成时
    • 任务状态改变时
    • 时间片用完时
    • 优先级改变时

调度器源码简析

// 调度器核心(简化版)
void rt_schedule(void)
{
    // 1. 查找最高优先级就绪任务
    struct rt_thread *to_thread;
    to_thread = _get_highest_priority_thread();
    
    // 2. 检查是否需要切换
    if (to_thread != rt_current_thread) {
        // 3. 执行上下文切换
        rt_hw_context_switch((rt_uint32_t)&rt_current_thread->sp,
                            (rt_uint32_t)&to_thread->sp);
    }
}

🎯 调度示例

示例1:优先级演示

#include <rtthread.h>

static rt_thread_t tid1, tid2, tid3;

static void thread1_entry(void *parameter)
{
    rt_uint32_t count = 0;
    
    while (1) {
        rt_kprintf("thread1 count: %d\n", count++);
        rt_thread_mdelay(500);  // 延时500ms
    }
}

static void thread2_entry(void *parameter)
{
    rt_uint32_t count = 0;
    
    while (1) {
        rt_kprintf("thread2 count: %d\n", count++);
        rt_thread_mdelay(1000); // 延时1s
    }
}

static void thread3_entry(void *parameter)
{
    rt_uint32_t count = 0;
    
    while (1) {
        rt_kprintf("thread3 count: %d\n", count++);
        rt_thread_mdelay(2000); // 延时2s
    }
}

int scheduler_demo(void)
{
    // 创建三个不同优先级的线程
    tid1 = rt_thread_create("thread1", thread1_entry, RT_NULL,
                           1024, 6, 10);
    tid2 = rt_thread_create("thread2", thread2_entry, RT_NULL,
                           1024, 7, 10);
    tid3 = rt_thread_create("thread3", thread3_entry, RT_NULL,
                           1024, 8, 10);
    
    // 启动线程
    if (tid1 != RT_NULL) rt_thread_startup(tid1);
    if (tid2 != RT_NULL) rt_thread_startup(tid2);
    if (tid3 != RT_NULL) rt_thread_startup(tid3);
    
    return 0;
}

示例2:时间片轮转

#include <rtthread.h>

#define THREAD_STACK_SIZE   512
#define THREAD_PRIORITY     10
#define THREAD_TIMESLICE    5  // 5个tick的时间片

static void thread_entry(void* parameter)
{
    rt_uint32_t value;
    rt_uint32_t count = 0;
    
    value = (rt_uint32_t)parameter;
    
    while (1) {
        rt_kprintf("thread %d is running, count = %d\n", value, count++);
        
        // 长时间运行,测试时间片切换
        for (int i = 0; i < 1000000; i++);
    }
}

int timeslice_demo(void)
{
    rt_thread_t tid;
    
    // 创建两个相同优先级的线程
    tid = rt_thread_create("thread1",
                          thread_entry,
                          (void*)1,
                          THREAD_STACK_SIZE,
                          THREAD_PRIORITY,
                          THREAD_TIMESLICE);
    if (tid != RT_NULL)
        rt_thread_startup(tid);
    
    tid = rt_thread_create("thread2",
                          thread_entry,
                          (void*)2,
                          THREAD_STACK_SIZE,
                          THREAD_PRIORITY,
                          THREAD_TIMESLICE);
    if (tid != RT_NULL)
        rt_thread_startup(tid);
    
    return 0;
}

🔍 调度调试技巧

1. 使用 Finsh 命令

# 查看线程状态
list_thread

# 输出示例
thread   pri  status      sp     stack size max used left tick  error
-------- ---  ------- ---------- ----------  ------  ---------- ---
thread1   10  running 0x00000060 0x00000200    28%   0x0000000a 000
thread2   10  ready   0x00000060 0x00000200    30%   0x0000000a 000
tshell    20  ready   0x00000080 0x00001000    15%   0x0000000a 000

2. 调度器钩子函数

// 注册调度器钩子
void my_scheduler_hook(struct rt_thread* from, struct rt_thread* to)
{
    rt_kprintf("switch from [%s] to [%s]\n", from->name, to->name);
}

// 安装钩子
rt_scheduler_sethook(my_scheduler_hook);

⚠️ 注意事项

  1. 优先级反转问题

    • 使用互斥锁的优先级继承机制
    • 避免高优先级任务等待低优先级任务
  2. 堆栈大小设置

    • 根据函数调用深度合理设置
    • 使用 list_thread 检查堆栈使用率
  3. 中断处理

    • 中断中不能使用可能导致阻塞的API
    • 快速处理,将耗时操作放到线程中
  4. 死锁预防

    • 按固定顺序获取多个锁
    • 设置超时机制

📊 性能优化建议

  1. 减少上下文切换

    • 合理设置时间片大小
    • 避免频繁创建/删除线程
  2. 优先级设置策略

    • I/O密集型任务:较低优先级
    • 计算密集型任务:较高优先级
    • 实时任务:最高优先级
  3. 使用静态线程

    // 静态线程创建(无动态内存分配)
    static struct rt_thread thread;
    static rt_uint8_t thread_stack[512];
    
    rt_thread_init(&thread, "static",
                   thread_entry, RT_NULL,
                   &thread_stack[0], sizeof(thread_stack),
                   10, 10);
    

需要我详细讲解调度算法实现、优先级反转解决方案或具体应用场景吗?

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐