RT-Thread线程管理全解析 — 创建、调度与生命周期

前言

线程是RT-Thread中最小的调度单位,理解线程管理是掌握RTOS的基础。本文将详细介绍线程的概念、状态转换、优先级机制以及创建和调度方法,并通过代码实例帮助你快速上手。


一、线程的概念

可以把多线程系统想象成一个繁忙的工厂:工人(线程)各自负责特定任务,调度员(调度器)负责分配工作,确保最重要的任务优先完成。

在 RT-Thread 中,线程是最小的工作单元。你可以将一个大任务拆分成多个线程,各自负责不同部分(如读取传感器、更新显示屏),系统根据优先级自动调度。


二、线程的组成部分

每个线程由三个核心部分组成:

组成部分 说明 比喻
线程控制块 记录线程名字、优先级、状态等信息 工人的身份证
线程栈 保存线程执行过程中的临时数据 工人的工具箱
入口函数 定义线程具体要做什么 工人的任务说明书

三、线程的状态

线程有五种状态:

状态 说明
初始状态 线程刚创建,尚未开始运行
就绪状态 准备好执行,等待调度器分配CPU
运行状态 正在使用CPU执行任务
挂起状态 暂停执行,等待资源或事件(如定时器到期、信号量释放)
关闭状态 任务完成或被删除,线程生命周期结束

状态转换路径:初始 → 就绪 → 运行 ↔ 挂起 → 关闭


四、线程优先级

RT-Thread 支持 256 个优先级(0-255),数字越小优先级越高。0 为最高优先级,系统空闲线程分配最低优先级。

调度规则:

  • 调度器总是选择优先级最高的就绪线程运行。
  • 高优先级线程可以抢占低优先级线程(全抢占式调度)。

可通过配置将优先级数量裁剪为 32 或 8 个,以节省资源。


五、时间片

当多个线程具有相同优先级时,系统使用时间片轮转机制:每个线程分配固定的时间片,轮流执行。

例如:线程 A 时间片为 10,线程 B 时间片为 5,则 A 执行 10 个时间单位后切换到 B,B 执行 5 个时间单位后再切换回 A。


六、创建线程:rt_thread_create

6.1 函数原型

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);

6.2 参数说明

参数 说明 示例
name 线程名称,用于调试标识 "led_ctrl"
entry 入口函数,线程具体执行的逻辑 led_thread_entry
parameter 传递给入口函数的参数 RT_NULL(无参数)
stack_size 线程栈大小(字节)。简单任务512,复杂任务1024+ 512
priority 优先级,0最高,数值越大越低 25
tick 时间片大小,仅在同优先级线程间生效 5

6.3 基础示例

#include <rtthread.h>

static rt_thread_t tid1 = RT_NULL;

static void thread1_entry(void *parameter)
{
    int count = 0;
    while (1)
    {
        rt_kprintf("Thread 1 is running, count: %d\n", count);
        count++;
        rt_thread_mdelay(1000);  // 休息1秒
    }
}

int main(void)
{
    tid1 = rt_thread_create("thread1",
                            thread1_entry, RT_NULL,
                            1024, 20, 10);

    if (tid1 != RT_NULL)
        rt_thread_startup(tid1);

    return 0;
}

6.4 LED 控制线程示例

#include <rtthread.h>

#define LED_STACK_SIZE    512
#define LED_PRIORITY      25
#define LED_TICK          5

void led_thread_entry(void *parameter)
{
    rt_kprintf("LED Thread Running...\n");
    while (1)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);  // 点亮LED
        rt_thread_mdelay(500);
        rt_pin_write(LED_PIN, PIN_LOW);   // 熄灭LED
        rt_thread_mdelay(500);
    }
}

int main(void)
{
    rt_thread_t led_thread = rt_thread_create("led_ctrl",
                                              led_thread_entry,
                                              RT_NULL,
                                              LED_STACK_SIZE,
                                              LED_PRIORITY,
                                              LED_TICK);
    if (led_thread != RT_NULL)
        rt_thread_startup(led_thread);

    return 0;
}

七、rt_thread_mdelay vs 普通 delay

这是从裸机开发迁移到RTOS时最重要的认知转变之一。

7.1 核心区别

区别点 rt_thread_mdelay 普通 delay_ms
是否释放CPU 是,线程进入挂起状态 否,CPU忙等待
系统调度 支持多线程调度和切换 无法调度其他任务
功耗管理 可进入低功耗模式 CPU一直忙等待
适用环境 多线程RTOS环境 单任务裸机环境

7.2 通俗理解

  • 普通 delay:在咖啡店柜台前干等,什么都不做,浪费时间。
  • rt_thread_mdelay:排队时先去做别的事情,等时间到了再回来,不浪费时间。

7.3 工作机制

rt_thread_mdelay 的调用流程:

  1. 当前线程进入 RT_THREAD_SUSPEND(挂起状态)
  2. 调度器切换到其他就绪线程执行
  3. 延时结束后,线程恢复为就绪状态,等待调度

关键原则:在RTOS环境中,永远不要使用忙等待的delay,应使用 rt_thread_mdelay 让出CPU资源。


八、线程调度与空闲线程

8.1 调度机制

调度器始终选择优先级最高的就绪线程执行。当高优先级线程完成任务或主动让出CPU时,调度器切换到下一个就绪线程。

8.2 空闲线程

空闲线程是优先级最低的系统线程,在没有其他任务运行时执行,负责:

  • 回收已完成线程的资源
  • 执行用户注册的空闲钩子函数

九、实战:多线程交替执行

#include <rtthread.h>

#define THREAD_PRIORITY    25
#define THREAD_STACK_SIZE  1024
#define THREAD_TIMESLICE   5

static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;

static void thread1_entry(void *parameter)
{
    int count = 0;
    while (count < 10)
    {
        rt_kprintf("Thread 1 is running, count: %d\n", count);
        count++;
        rt_thread_mdelay(1000);
    }
}

static void thread2_entry(void *parameter)
{
    int count = 0;
    while (count < 10)
    {
        rt_kprintf("Thread 2 is running, count: %d\n", count);
        count++;
        rt_thread_mdelay(1000);
    }
}

int main(void)
{
    tid1 = rt_thread_create("thread1",
                            thread1_entry, RT_NULL,
                            THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);

    tid2 = rt_thread_create("thread2",
                            thread2_entry, RT_NULL,
                            THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);

    if (tid1 != RT_NULL) rt_thread_startup(tid1);
    if (tid2 != RT_NULL) rt_thread_startup(tid2);

    return 0;
}

两个线程优先级和时间片相同,调度器让它们轮流执行,各自输出计数值。当线程调用 rt_thread_mdelay(1000) 时让出CPU,另一个线程获得执行机会。


总结

要点 内容
线程组成 控制块 + 栈 + 入口函数
状态模型 初始 → 就绪 → 运行 ↔ 挂起 → 关闭
调度策略 优先级抢占 + 同级时间片轮转
创建方式 rt_thread_create + rt_thread_startup
延时选择 RTOS中必须使用 rt_thread_mdelay,禁止忙等待delay

掌握了线程管理,你就掌握了RTOS的核心。下一篇将介绍时钟与定时器管理,探索RT-Thread如何处理时间维度的任务调度。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐