2. 线程动态创建与静态创建

任务目标

在RT-Thread中,线程有两种创建方式:动态创建(rt_thread_create)和静态初始化(rt_thread_init)。两者的核心区别在于线程控制块和线程栈的内存来源:动态创建由系统从堆中自动分配,静态初始化则需要用户预先定义并传入。本案例分别用两种方式创建两个线程,通过串口输出验证它们都能独立运行,并直观理解静态线程的内存分配方式。

核心实现

动态创建使用rt_thread_create(),只需传入入口函数、参数、栈大小等参数,系统内部完成struct rt_thread和栈空间的堆分配。静态初始化使用rt_thread_init(),需要用户预先定义static struct rt_thread线程控制块和static rt_uint8_t栈数组,初始化后通过rt_thread_startup()启动。两种方式启动后的调度行为完全一致。

```c #include /* 静态线程需要预先分配的控制块和栈 */ static struct rt_thread static_thread; static rt_uint8_t static_thread_stack[512]; /* 线程入口函数 */ static void thread_entry(void *parameter) { rt_uint32_t count = 0; const char *name = (const char *)parameter; while (1) { rt_kprintf("%s is running, count = %d\n", name, count++); rt_thread_mdelay(1000); /* 延时1秒 */ } } /* 动态线程控制块指针 */ static rt_thread_t dynamic_thread = RT_NULL; int thread_create_sample(void) { /* 1. 动态创建:控制块和栈由系统从堆中分配 */ dynamic_thread = rt_thread_create("dyn", thread_entry, (void *)"dynamic", 512, /* 栈大小 */ 20, /* 优先级 */ 10); /* 时间片 */ if (dynamic_thread != RT_NULL) rt_thread_startup(dynamic_thread); else rt_kprintf("dynamic thread create failed\n"); /* 2. 静态初始化:控制块和栈由用户预先定义 */ rt_err_t result = rt_thread_init(&static_thread, "sta", thread_entry, (void *)"static", static_thread_stack, sizeof(static_thread_stack), 21, /* 优先级 */ 10); /* 时间片 */ if (result == RT_EOK) rt_thread_startup(&static_thread); else rt_kprintf("static thread init failed\n"); return 0; } /* 自动初始化:系统启动后自动调用 */ INIT_APP_EXPORT(thread_create_sample); ```

运行与验证

编译与下载:本案例基于RT-Thread Studio或Env环境,在任意支持RT-Thread的BSP工程中新建main.c并粘贴上述代码,编译后下载至开发板。

预期串口输出:系统启动后,两个线程交替打印(调度顺序由优先级决定,动态线程优先级20略高,会先运行):

dynamic is running, count = 0
static is running, count = 0
dynamic is running, count = 1
static is running, count = 1
...

通过条件:串口终端能看到dynamic和static两个线程各自循环打印且计数递增,说明两种创建方式均成功运行。若只出现一个线程的输出,检查另一个线程的优先级是否被占用或栈大小是否不足。

关键区别说明

对比项动态创建静态初始化
APIrt_thread_create()rt_thread_init()
控制块来源堆(rt_malloc)用户定义的全局变量
栈来源堆(rt_malloc)用户定义的全局数组
释放方式rt_thread_delete()rt_thread_detach()
适用场景线程数量/栈大小运行时才确定资源固定、避免堆碎片
内存理解要点:静态线程的static_thread控制块和static_thread_stack[512]数组都位于全局数据区(.bss段),在编译链接时地址已确定,不占用堆空间。动态线程的dynamic_thread指针本身在栈上,但它指向的struct rt_thread和512字节栈均在堆中分配。观察rt_thread_init的参数——需要显式传入控制块地址和栈地址,这正是静态方式“内存由用户提供”的体现。

常见问题

  • 静态线程初始化失败:检查传入的栈地址是否8字节对齐(RT-Thread要求栈起始地址对齐),以及控制块是否重复初始化。
  • 动态创建返回RT_NULL:通常是堆空间不足,可调大HEAP_SIZE或改用静态方式。
  • 两个线程只有一个运行:确认两个线程优先级不同(本案例为20和21),相同优先级时需依赖时间片轮转,且两个线程都需在循环中主动让出CPU(如rt_thread_mdelay)。