自学内容网 自学内容网

RT-Thread之线程管理(线程的基础概念和使用)


前言

本篇文章来给大家讲解RT-Thread中的线程管理,线程管理是属于最基础的部分,这篇文章将带大家学习如何在RT-Thread使用线程。

一、RT-Thread线程的概念

线程:在 RT-Thread 中,线程是程序执行的基本单元。每个线程都拥有自己的独立栈空间和执行上下文,可以独立运行。RT-Thread 使用线程来实现并发执行,允许多个线程同时执行不同的任务。

线程的特点:

轻量级:RT-Thread 的线程管理采用了轻量级的设计,使得创建、切换和销毁线程的开销非常小。

独立性:每个线程都是独立运行的,拥有自己的栈空间和执行上下文,不受其他线程的影响。

并发执行:多个线程可以同时执行,通过时间片轮转或优先级调度来实现并发执行。

可抢占:RT-Thread 支持线程的抢占式调度,高优先级线程可以抢占低优先级线程的执行权。

二、线程的创建与删除

2.1用户线程和系统线程

用户线程:

功能:用户线程是由应用程序开发者创建和管理的线程,用于执行应用程序的业务逻辑。这些线程通常用于处理特定的任务、算法或功能模块,例如传感器数据采集、通信协议处理、用户界面操作等。

特点:用户线程的创建、销毁和调度由应用程序开发者控制,可以根据应用程序的需要动态地创建和管理线程。
典型应用:用户线程通常用于实现应用程序的各个功能模块,是应用程序的核心部分。

系统线程:

功能:系统线程是由 RT-Thread 内核创建和管理的线程,用于执行系统级的任务和服务。这些线程通常用于实现 RT-Thread 内核的基本功能,如时钟管理、内存管理、设备驱动、任务调度等。

特点:系统线程的创建、销毁和调度由 RT-Thread 内核自动管理,通常在系统初始化阶段就会被创建,并在整个系统运行期间保持运行。
典型应用:系统线程通常用于支持 RT-Thread 内核的正常运行,提供各种系统级的服务和功能。

这两类线程都会从内核对象容器中分配线程对象,如下图所示。 每个线程由三部分组成:线程控制块(rt_thread 结构体)、线程栈和入口函数。

在这里插入图片描述

2.2线程控制块

线程控制块由结构体 struct rt_thread 表示,线程控制块是操作系统用于管理线程的一个数据结构。

它存放线程的一些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之间连接用的链表结构,线程等待事件集合等。

它在 rtdef.h 中定义如下:

/**
* Thread structure
*/
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_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; /* 用户私有数据*/
};
typedef struct rt_thread *rt_thread_t;

2.3线程栈

概念:线程栈是用来存储线程执行过程中的局部变量、函数调用信息以及线程执行状态的一段内存空间。每个线程都拥有自己独立的线程栈,用于保存线程的执行上下文。

作用:线程栈在线程执行期间起到了重要作用,它保存了线程执行过程中的临时数据和状态信息,保证了线程的独立性和安全性。

大小:线程栈的大小通常由用户在创建线程时指定,根据线程的具体任务和需求来确定。过小的线程栈可能导致栈溢出,而过大的线程栈则会浪费内存资源。

2.4入口函数

概念:线程入口函数是线程创建时指定的一个函数,线程在启动时将从该函数开始执行。通常情况下,线程入口函数负责执行线程的实际任务逻辑,并在任务完成后终止线程的执行。

特点:线程入口函数可以是任何符合特定格式的函数,通常以特定的参数和返回值形式定义。在函数内部,开发者可以编写线程的具体逻辑,完成所需的任务。

参数:线程入口函数通常接受一个参数,这个参数可以是任意类型的数据,用于传递给线程的任务逻辑所需的参数信息。

返回值:线程入口函数通常没有返回值,或者返回一个表示执行结果或错误码的值。

三、线程的创建和启动

3.1线程创建的种类

静态创建:

概念:静态创建是指在编译时确定线程栈和线程控制块的大小,并在初始化阶段就创建好线程的方法。这种方法需要在编译时确定线程的数量和属性,线程的生命周期与系统的生命周期一致。

特点:静态创建的线程在系统初始化时创建,并且在整个系统运行期间保持不变。静态创建的线程在内存中占用固定的空间,不会动态增加或减少。

动态创建:

概念:动态创建是指在运行时根据需要创建线程的方法。这种方法允许在运行时根据系统的实际需求动态地创建和销毁线程,灵活性更高。
特点:动态创建的线程可以根据系统的运行状态和需求进行动态调整,从而更好地适应不同的应用场景。

3.2动态创建线程

rt_thread_init() 函数:

参数:
thread:线程控制块(Thread Control Block, TCB),用于指定要初始化的线程的属性和初始化信息。
name:线程的名称,用于标识线程。
entry:线程的入口函数,即线程启动后要执行的函数。
parameter:线程入口函数的参数,可以是任意类型的数据,用于传递给线程入口函数。
stack_start:线程的栈起始地址,即线程栈的起始位置。
stack_size:线程栈的大小,以字节为单位。
priority:线程的优先级,用于确定线程在系统中的执行顺序。
tick:线程的时间片,即线程在运行后执行的时间。

返回值:
该函数无返回值。

示例代码:

#include <rtthread.h>

static struct rt_thread thread; // 定义线程控制块
static char thread_stack[512];   // 定义线程栈

void thread_entry(void* parameter)
{
    // 线程的入口函数,实现线程的具体逻辑
}

int main(void)
{
    // 初始化线程
    rt_thread_init(&thread, "my_thread", thread_entry, NULL, thread_stack, sizeof(thread_stack), 10, 20);
    // 启动线程
    rt_thread_startup(&thread);
    return 0;
}

3.3静态创建线程

rt_thread_create() 函数:

参数:
name:线程的名称,用于标识线程。
entry:线程的入口函数,即线程启动后要执行的函数。
parameter:线程入口函数的参数,可以是任意类型的数据,用于传递给线程入口函数。
stack_size:线程栈的大小,以字节为单位。
priority:线程的优先级,用于确定线程在系统中的执行顺序。
tick:线程的时间片,即线程在运行后执行的时间。
返回值:
成功创建线程时返回线程控制块指针,失败时返回 NULL。

示例代码:

#include <rtthread.h>

void thread_entry(void* parameter)
{
    // 线程的入口函数,实现线程的具体逻辑
}

int main(void)
{
    // 创建线程
    rt_thread_t tid = rt_thread_create("my_thread", thread_entry, NULL, 512, 10, 20);
    // 启动线程
    if (tid != RT_NULL) {
        rt_thread_startup(tid);
    }
    return 0;
}

总结

本篇文章我们主要给大家讲解了RT-Thread中的线程的一些基础概念和基础使用方法。


原文地址:https://blog.csdn.net/m0_49476241/article/details/138275664

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!