线程概述:
在裸机系统中,系统的主体就是main函数中按顺序下执行代码'在循环中CPU完成各种操作;
在多线程系统;根据功能不同分成许多独立实现功能的小程序;将其称为线程。

静态线程与动态线程定义
静态线程在程序启动时创建,数量固定,生命周期与程序一致。动态线程在运行时按需创建和销毁,数量可调整。
静态线程特点
- 资源分配:启动时预分配内存和系统资源,开销集中在初始化阶段。
- 适用场景:任务数量已知且稳定,如服务器固定工作线程池。
- 局限性:无法灵活应对任务量波动,可能造成资源浪费或性能瓶颈。
动态线程特点
- 灵活性:根据负载动态创建或回收线程,适应任务量变化。
- 开销:频繁创建/销毁引入运行时开销,需管理线程生命周期。
- 适用场景:任务突发性强或不可预测,如实时请求处理。
性能考量
- 静态线程:减少锁竞争和上下文切换,但空闲线程占用资源。
- 动态线程:资源利用率高,但频繁创建/销毁可能导致延迟。
选择建议
- 需要低延迟和确定性时选择静态线程。
- 处理波动负载且资源有限时优先动态线程。
准备工作(源码下载初始化工程)可以在官网查看教程。这里直接跳过;
1:静态线程的创建:
初始化线程
静态线程的线程句柄(或者说线程控制块指针)、线程栈由用户提供。静态线程是指线程控制块、线程运行栈一般都设置为全局变量,在编译时就被确定、被分配处理,内核不负责动态分配内存空间。需要注意的是,用户提供的栈首地址需做系统对齐(例如ARM上需要做4字节对齐)。线程初始化接口函数rtthreadinit()的参数和返回值见下表:

现在我们开始教学1个静态线程的创建;以及创建的步骤:
cs
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t flag1_thread_stack[512];
static struct rt_thread flag1_thread;
rt_thread_init(
&flag1_thread,
"flag1",
flag1_thread_entry,
RT_NULL,
&flag1_thread_stack[0],
sizeof(flag1_thread_stack),
3,
20);
rt_thread_startup(&flag1_thread); //启动线程
static void flag1_thread_entry(void* param)
{
while(1)
{
flag1=1;
rt_thread_mdelay(200);
flag1=0;
rt_thread_mdelay(200);
}
}
//ALIGN(RT_ALIGN_SIZE) 宏用于确保栈在内存中的对齐满足RTOS的要求。
//flag1_thread_stack 被定义为一个512字节的静态数组,这个数组将作为线程的栈使用。
static struct rt_thread flag1_thread;
//这一行声明了一个线程结构体(flag1_thread),该结构体将保存有关线程的信息,例如状态、优先级和其他属性
&flag1_thread:传入的线程结构体的地址,表示要初始化的线程。
"flag1":线程的名字,以字符串形式表示,方便调试和管理。
flag1_thread_entry:线程的入口函数,即线程创建后执行的函数。
RT_NULL:传入的参数,表示线程入口函数不需要参数。如果需要,可以传入其他数据。
&flag1_thread_stack[0]:线程栈的起始地址,使用前面定义的栈数组。
sizeof(flag1_thread_stack):栈的大小,确保分配足够的内存给线程执行时使用。
3:线程的优先级,数值越小,优先级越高。在此示例中,优先级为3。
20:时间片,通常用于时间共享调度的单位,表示线程在运行时的最大时间。
2:动态线程的创建:
一个线程要成为可执行的对象,就必须由操作系统的内核来为它创建一个线程。可以通过rt_thread_create创建一个动态线程:调用这个函数时,系统会从动态堆内存中分配一个线程句柄以及按照参数中指定的栈大小从动态堆内存中分配相应的空间。分配出来的栈空间是按照rtconfig.h中配置的RT_ALIGN_SIZE方式对齐。线程创建rt threadcreate(的参数和返回值见下表:

现在开始创建一个动态线程代码:
cs
#include <rtthread.h>
static rt_uint8_t flag2 = 0; // 定义全局标志变量
static rt_thread_t flag2_thread = RT_NULL; // 线程句柄
static void flag2_thread_entry(void* parameter)
{
while (1)
{
flag2 = 1; // 设置标志为1
rt_thread_mdelay(200); // 延迟200毫秒
flag2 = 0; // 将标志设置回0
rt_thread_mdelay(200); // 再延迟200毫秒
}
}
void thread_create(void)
{
flag2_thread = rt_thread_create("flag2", flag2_thread_entry, RT_NULL, 512, 3, 20);
if (flag2_thread != RT_NULL) // 确保线程创建成功
{
rt_thread_startup(flag2_thread); // 启动线程
}
else
{
rt_kprintf("线程创建失败!\n");
}
}
3:静态线程和动态线程的区别:
1. 定义
-
动态线程:
- 动态线程是在运行时创建的线程,通常通过调用特定的API(如
rt_thread_create())来实现。 - 线程的创建和销毁可以根据需要进行,而不是在程序编译时就确定好。
- 动态线程是在运行时创建的线程,通常通过调用特定的API(如
-
静态线程:
- 静态线程是在编译时就定义好的线程,通常使用全局或静态变量来管理。
- 这些线程在程序启动时初始化,生命周期与程序的运行周期相同,通常不会被动态创建或销毁。
2. 创建和销毁
-
动态线程:
- 可以根据需要随时创建和销毁,灵活性强。
- 适合于任务量不确定或变化频繁的场景,能够有效利用系统资源。
- 例如,在RTOS中,可以在不同的事件触发下动态生成或释放线程。
-
静态线程:
- 在程序启动时一次性创建,生命周期固定。
- 适合于任务量固定且在整个程序运行期间都需要执行的情况。
- 所有线程在程序编译时就已经确定,不支持根据运行时条件进行调整。
3. 内存管理
-
动态线程:
- 在创建线程时需要分配堆内存,运行时管理内存,可能导致内存碎片问题。
- 需要注意线程的创建和销毁,避免内存泄漏。
-
静态线程:
- 使用静态分配的内存(如全局或局部静态变量),内存管理简单。
- 不会出现内存碎片问题,但占用的内存是在程序启动时就确定了,无法灵活调整。
4. 性能
-
动态线程:
- 创建和销毁线程的开销相对较大,因为涉及到内存分配和调度。
- 在高负载情况下,频繁创建和销毁线程可能影响性能。
-
静态线程:
- 由于线程在程序启动时就已创建,运行时没有创建和销毁的开销,响应速度更快。
- 更加适合于实时性要求高的应用场景。
5. 灵活性和可维护性
-
动态线程:
- 提供更大的灵活性,能够根据实际需求增减线程数量,适应变化的工作负载。
- 代码可能更复杂,需要处理更多的线程状态和生命周期管理。
-
静态线程:
- 代码结构相对简单,易于理解和维护。
- 但缺乏灵活性,一旦设计完成,便很难根据需求变化进行调整。
代码运行结果:

需要代码工程的可以私信😉