在RT-Thread实时操作系统中,创建线程可以通过以下两种方式实现:
动态创建线程
动态创建线程是指在运行时根据需要动态分配线程所需的内存资源(控制块和堆栈)。这种方式适用于需要在程序运行过程中灵活创建和销毁线程的场景。
API函数: rt_thread_create()
函数原型:
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)
参数说明:
name
:线程的名字,用于标识和调试。entry
:线程的入口函数,线程开始执行时调用的第一个函数。parameter
:传递给线程入口函数的参数,用于传递线程私有数据。stack_size
:线程堆栈大小,单位为字节。priority
:线程优先级,取值范围通常为0至系统最大优先级数(如255)。tick
:线程的时间片数,用于时间片轮转调度。对于大多数应用,可以设置为0,表示不使用时间片轮转。
返回值:
- 成功创建并初始化线程后,返回指向新创建线程的指针。
- 创建失败(如内存不足等原因),返回
RT_NULL
。
示例代码:
static void my_thread_entry(void *arg)
{
// 线程执行的代码...
}
int main(void)
{
rt_thread_t my_thread;
my_thread = rt_thread_create("my_thread",
my_thread_entry, NULL, /* 入口函数与参数 */
2048, /* 堆栈大小 */
20, /* 优先级 */
0); /* 时间片数 */
if (my_thread != RT_NULL)
{
rt_thread_startup(my_thread); // 启动线程
}
else
{
// 创建失败,处理错误...
}
return 0;
}
静态创建线程
静态创建线程是指在编译阶段就为线程预留好控制块和堆栈空间,通常在全局或静态变量区分配。这种方式适用于资源受限或对实时性要求较高的场景,可以减少运行时的内存分配开销。
API函数: rt_thread_init()
函数原型:
rt_err_t rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)
参数说明:
thread
:指向已定义的线程控制块的指针。name
:线程的名字,用于标识和调试。entry
:线程的入口函数,线程开始执行时调用的第一个函数。parameter
:传递给线程入口函数的参数,用于传递线程私有数据。stack_start
:线程堆栈的起始地址,指向之前定义的堆栈数组。stack_size
:线程堆栈大小,单位为字节。priority
:线程优先级,取值范围通常为0至系统最大优先级数(如255)。tick
:线程的时间片数,用于时间片轮转调度。对于大多数应用,可以设置为0,表示不使用时间片轮转。
返回值:
RT_EOK
:表示操作成功。这是一个常量,通常定义为0或一个特定的正数,表示没有错误发生。- 创建失败,返回负数值:通常代表各种具体的错误代码(
RT_ETIMEOUT
,RT_EBUSY
等),每个数值对应一种特定的错误情况。
示例代码:
#include <rtthread.h>
/* 定义线程控制块 */
static struct rt_thread my_thread;
/* 定义堆栈空间 */
static rt_uint8_t my_thread_stack[2048];
static void my_thread_entry(void *arg)
{
// 线程执行的代码...
}
int main(void)
{
/* 初始化线程 */
rt_thread_init(&my_thread, "my_thread", /* 线程名 */
my_thread_entry, NULL, /* 入口函数与参数 */
&my_thread_stack[0], /* 堆栈起始地址 */
sizeof(my_thread_stack), /* 堆栈大小 */
20, /* 优先级 */
0); /* 时间片数 */
rt_thread_startup(&my_thread); // 启动线程
return 0;
}
无论是动态创建还是静态创建线程,创建成功后均需通过rt_thread_startup()函数启动线程,使其进入就绪态并可能立即投入运行。创建失败时,应妥善处理错误情况,避免资源泄漏或系统异常。
线程控制块(TCB)
线程控制块(Thread Control Block, TCB)是操作系统中用于管理和控制线程的数据结构。它是线程在系统中的核心表示,存储了线程的关键属性、状态信息以及与线程生命周期管理相关的数据。以下是对线程控制块(TCB)的详细介绍:
作用与目的
线程标识与状态记录:TCB作为线程的唯一标识,记录线程的唯一标识符(线程ID)和当前状态(如就绪、运行、挂起、阻塞、结束等),使得操作系统能够准确跟踪和控制各个线程的执行情况。
调度信息:TCB包含线程的优先级、时间片、调度策略等信息,这些数据是操作系统调度器进行线程调度决策的依据,确保线程能在适当的时机获得CPU资源。
上下文保存与切换:TCB存储了线程执行时的CPU寄存器状态(如程序计数器PC、通用寄存器、状态寄存器等),当发生线程上下文切换时,这些信息会被保存到当前线程的TCB中,同时从即将运行的线程TCB中加载相应的寄存器状态,从而实现线程执行现场的切换。
资源关联:TCB关联了线程使用的系统资源,如线程私有堆栈、共享资源的锁定状态、等待队列链接等,这些信息对于线程间的同步与通信、资源分配与回收至关重要。源码
/* 线程控制块 */
struct rt_thread
{
/* rt 对象 */
char name[RT_NAME_MAX]; /* 线程名称 */
rt_uint8_t type; /* 对象类型 */
rt_uint8_t flags; /* 标志位 */
rt_list_t list; /* 对象列表 */
rt_list_t tlist; /* 线程列表 */
/* 栈指针与入口指针 */
void *sp; /* 栈指针 */
void *entry; /* 入口函数指针 */
void *parameter; /* 参数 */
void *stack_addr; /* 栈地址指针 */
rt_uint32_t stack_size; /* 栈大小 */
/* 错误代码 */
rt_err_t error; /* 线程错误代码 */
rt_uint8_t stat; /* 线程状态 */
/* 优先级 */
rt_uint8_t current_priority; /* 当前优先级 */
rt_uint8_t init_priority; /* 初始优先级 */
rt_uint32_t number_mask;
......
rt_ubase_t init_tick; /* 线程初始化计数值 */
rt_ubase_t remaining_tick; /* 线程剩余计数值 */
struct rt_timer thread_timer; /* 内置线程定时器 */
void (*cleanup)(struct rt_thread *tid); /* 线程退出清除函数 */
rt_uint32_t user_data; /* 用户数据 */
};
动态/静态创建线程区别
动态创建线程和静态创建线程在RT-Thread实时操作系统中有以下几个主要区别:
内存分配时机与方式:
- 动态创建:在线程创建时(运行时),通过内存分配函数(如
rt_malloc()
)从动态内存堆中动态分配线程控制块和堆栈空间。创建的线程可以在程序运行过程中随时创建、启动、销毁,具有较高的灵活性。 - 静态创建:在编译阶段就已经为线程预留好控制块和堆栈空间,通常在全局或静态变量区静态分配。这样可以避免运行时的内存分配操作,适合资源有限或对实时性要求高的场景。
内存管理成本与效率:
- 动态创建:由于涉及到运行时的内存分配和释放,可能存在一定的内存管理开销,如查找可用内存、分配内存块、维护内存管理数据结构等。尤其是在内存碎片严重或内存池不足时,分配效率可能会下降。
- 静态创建:预先分配好的内存无需运行时管理,因此省去了动态内存分配的开销,创建和销毁线程的效率通常更高。但如果静态分配的资源过多,可能会增加程序的总体内存占用,特别是在资源有限的嵌入式系统中需要注意。
资源限制与可扩展性:
- 动态创建:理论上可以创建任意数量的线程(受总内存大小限制),适应性强,适用于需要根据运行时条件动态调整线程数量的应用。
- 静态创建:线程数量受到编译时预定义的静态资源限制,扩展性相对较差,适用于线程数量固定或变化范围较小的场景。
内存泄漏风险:
- 动态创建:若忘记在适当时候调用
rt_thread_delete()
删除动态创建的线程,可能导致内存泄漏。需要确保在程序退出或线程不再需要时正确释放资源。 - 静态创建:由于使用的是全局或静态内存,不存在忘记释放的问题。但是,如果静态线程的生命周期管理不当,可能导致资源无法重用或浪费。
编程复杂度与可移植性:
- 动态创建:编程相对简单,只需调用
rt_thread_create()
即可创建线程,不需要手动管理线程控制块和堆栈。代码更易于理解和维护,且在不同平台或系统配置下移植性较好。 - 静态创建:需要手动定义线程控制块和堆栈,初始化时需要提供堆栈起始地址。代码稍显复杂,但对特定硬件平台的资源利用可能更为精细。
总结来说,动态创建线程和静态创建线程的主要区别在于内存分配的时间、方式、效率、可扩展性、资源管理风险以及编程复杂度。选择哪种方式取决于具体的应用需求、系统资源状况以及对实时性和代码管理的要求。在实际开发中,可以根据项目特点灵活运用这两种创建方式。
创建线程的代码例程已上传,需要获取自行获取
https://download.csdn.net/download/weixin_42530814/89218918?spm=1001.2014.3001.5501