购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.1 RT-Thread线程管理应用开发

线程管理是多任务操作系统的核心功能之一。线程管理涉及线程的创建、调度、同步和销毁等操作。线程是一个进程内的独立执行流,多线程的使用可以提高系统的并发性和实时性。有效的线程管理可以提高系统的性能和并发处理能力。

本节的要求如下:

➲ 了解线程的基本概念。

➲ 学习线程调度的机制。

➲ 掌握线程管理方式。

➲ 掌握RT-Thread线程管理的应用。

2.1.1 原理分析

2.1.1.1 线程管理简介

在日常生活中,要解决一个大问题,一般会将它分解成多个简单、容易解决的小问题,小问题逐个被解决后,大问题也就随之被解决了。在多线程操作系统中,同样也需要把一个复杂的应用分解成多个小的、可调度的、序列化的程序单元(模块)。合理划分任务并正确执行各个子任务的方式,能够提高系统的性能并满足实时性的要求。例如,嵌入式系统通常需要通过传感器采集数据、通过显示屏将数据显示出来。在多线程操作系统中,可以将嵌入式系统的任务分为两个子任务,即接收传感器数据和输出显示,如图2.1所示,一个子任务不间断地读取传感器数据,并将数据写到共享内存中,另一个子任务周期性地从共享内存中读取数据并将其显示到显示屏上。

图2.1 嵌入式系统的两个子任务

在RT-Thread中,与子任务对应的程序实体就是线程。线程是RT-Thread中最基本的调度单位,它不仅描述了一个任务执行的运行环境,还描述了这个任务的优先级。重要的任务可设置相对较高的优先级,不重要的任务可以设置较低的优先级,不同的任务还可以设置相同的优先级,轮流运行。

2.1.1.2 线程管理有关概念

(1)线程的创建和销毁。通过操作系统提供API可创建线程,如pthread_create(POSIX系统)或CreateThread(Windows系统)。销毁线程通常是由线程本身完成的,也可以在其他线程中调用特定API来终止目标线程。

(2)线程调度。操作系统通过调度算法来决定哪个线程在何时执行,这通常涉及线程的优先级、时间片分配和上下文切换。在切换线程时,需要保存和还原线程的上下文,包括寄存器状态和栈。

(3)线程的同步和互斥。互斥量用于保护临界区,防止多个线程同时访问共享资源,防止竞争条件(Race Conditions)。信号量用于控制多个线程的并发访问,限制资源的可用性。条件变量用于线程之间的协作,一个线程等待另一个线程发出通知。

(4)线程通信。①消息队列:线程可以通过消息队列相互通信,发送和接收消息。②共享内存:多个线程可以共享同一块内存区域,以进行数据交换。③管道和套接字:线程可以使用管道和套接字与其他进程进行通信。

(5)线程优先级。每个线程都具有一个优先级,用于决定该线程在调度时的执行顺序。高优先级的线程通常会被更早地调度执行。

(6)线程状态。线程可以处于不同的状态,如运行、就绪、阻塞等,具体的状态由操作系统管理。

(7)线程安全性。线程安全性是指多线程环境下,代码能够正确处理并发操作,不会导致数据损坏或不一致,编写线程安全的代码是至关重要的。

(8)线程池。线程池可以维护一组预创建的线程,以处理任务队列中的工作。线程池可以提高线程的重用性,减少线程创建和销毁的开销。

2.1.1.3 线程调度机制

RT-Thread线程管理的主要功能是对线程进行管理和调度。RT-Thread中的线程可分为两类:系统线程和用户线程。系统线程是由RT-Thread内核创建的,用户线程是由应用程序创建的。这两类线程在创建时都会从内核对象容器中分配线程对象,当销毁时都会删除对象容器中的线程对象。每个线程都有一些基本的属性,如线程控制块、线程栈、入口函数等。RT-Thread的线程管理如图2.2所示。

图2.2 RT-Thread线程管理

RT-Thread的线程调度器是抢占式的,主要的工作就是从就绪的线程列表中查找优先级最高的线程,保证优先级最高的线程能够被运行,优先级最高的线程一旦就绪,总能得到CPU的使用权。在某个线程的运行过程中,当某个优先级更高的线程满足运行条件时,正在运行的线程的CPU使用权就会被剥夺,优先级高的线程可立刻得到CPU使用权。如果中断服务程序使一个优先级高的线程满足运行条件,则在中断服务程序完成时,被中断的线程将被挂起,先运行优先级高的线程。当线程调度器调度线程时,先将当前线程的上下文保存起来;当切回到原来的线程时,线程调度器将恢复该线程的上下文。

2.1.1.4 线程管理方式

图2.3所示为线程的相关操作,包含创建/初始化线程、启动线程、运行线程、删除/脱离线程。通过rt_thread_create()函数可创建一个动态线程,通过rt_thread_init()函数可初始化一个静态线程。动态线程与静态线程的区别是:动态线程是系统自动从动态内存上分配栈空间与线程句柄的(初始化内存后才能使用rt_thread_create()函数创建动态线程),静态线程是由用户分配栈空间与线程句柄的。

图2.3 RT-Thread线程管理方式

1)创建线程

一个线程要成为可执行的对象,就必须由操作系统的内核来为它创建一个线程。通过下面的函数可创建一个动态线程:

2)删除线程

对于由rt_thread_create()函数创建的线程,在不需要使用该线程或者该线程运行出错时,可以使用下面的函数来删除线程:

3)启动线程

创建(初始化)的线程状态处于初始状态,并未进入就绪线程的调度队列。在线程初始化或创建成功时调用下面的函数可以令线程进入就绪态:

4)挂起线程

通过rt_thread_suspend()函数可以将线程主动挂起,通过rt_sem_take()、rt_mb_recv()函数可以在资源不可用时将线程挂起。处于挂起状态的线程,如果其等待的资源超时(超过其设定的等待时间),那么该线程将不再等待这些资源并返回到就绪状态;当其他线程释放掉该线程所等待的资源时,该线程也会返回到就绪状态。

5)恢复线程

恢复线程就是让挂起的线程重新进入就绪状态,并将其放入就绪线程的调度队列。如果被恢复线程在所有的就绪态线程中位于最高优先级链表的第一位,那么系统将进行线程上下文的切换。通过下面的函数可恢复线程:

2.1.2 开发设计与实践

2.1.2.1 硬件设计

本节的硬件设计同1.5.2.1节。

2.1.2.2 软件设计

软件设计流程如图2.4所示。

(1)创建LED线程,并且在main函数中完成线程的初始化工作。

(2)编写线程入口函数,在线程入口函数中完成LED引脚的初始化工作。

(3)当在MobaXterm串口终端FinSH控制台中输入“threadManage start”命令时,可启动LED线程,并进入线程入口函数中循环点亮4个LED灯;当输入“threadManage suspend”命令时,可挂起线程,4个LED停止循环点亮;当输入“threadManage resume”命令时,可恢复线程,4个LED继续循环点亮;当输入“threadManage delete”命令时,可删除线程,4个LED停止循环点亮,并且在系统中删除LED线程。

图2.4 软件设计流程

2.1.2.3 功能设计与核心代码设计

通过原理学习可知,要实现LED线程的管理,就需要使用RT-Thread提供的线程管理接口进行线程的初始化,并编写相应的线程入口函数。线程管理使用的是FinSH控制台命令,需要实现对应的控制命令,并将实现的命令添加到FinSH控制台命令列表中,这样在启动FinSH控制台后就可以使用自定义的FinSH控制台命令了。

1)主函数(zonesion/app/main.c)

主函数的主要工作是调用led_thread_init()函数,完成引导工作。代码如下:

2)线程初始化函数(zonesion/app/apl_led.c)

线程初始化函数实现线程的创建,包括定义线程名称、线程入口函数,设置线程内存大小、线程优先级、线程时间片等参数。代码如下:

3)线程入口函数(zonesion/app/apl_led.c)

线程入口函数实现LED引脚的初始化,并且在死循环中循环点亮LED。在线程启动后即可进入线程入口函数运行。代码如下:

4)自定义FinSH控制台命令函数(zonesion/app/finsh_cmd/finsh_ex.c)

自定义FinSH控制台命令函数实现LED线程管理的命令,包括线程的创建、挂起、恢复及删除,可以在FinSH控制台中使用命令对线程进行操作。代码如下:

2.1.3 开发步骤与验证

2.1.3.1 硬件部署

同1.2.3.1节。

2.1.3.2 工程调试

(1)将工程文件夹(05-Thread)复制到“RT-ThreadStudio/workspace”目录下。

(2)部署公共文件(02-软件资料/01-操作系统/rtt-common.zip):将rt-thread文件夹复制到工程的根目录、将zonesion/common文件夹复制到工程的zonesion目录下。

(3)使用RT-Thread Studio导入工程。

完成工程的编译、下载后即可进行调试。

2.1.3.3 验证效果

(1)关闭RT-Thread Studio,拔掉仿真器,按下ZI-ARMEmbed上的电源按键重新上电。

(2)在MobaXterm串口终端FinSH控制台中输入“threadManage start”命令,解析自定义FinSH控制台命令后,启动LED线程,4个LED循环点亮(见图2.5),同时FinSH控制台输出“led thread starting success!”信息。

图2.5 4个LED循环点亮

(3)在MobaXterm串口终端FinSH控制台中输入“threadManage suspend”命令,解析自定义FinSH控制台命令后,挂起LED线程,4个LED停止循环点亮,这时只有1个LED点亮,同时FinSH控制台输出“led thread suspend success!”信息。

(4)在MobaXterm串口终端FinSH控制台中输入“threadManage resume”命令,解析自定义FinSH控制台命令后,恢复LED线程,4个LED继续循环点亮,同时FinSH控制台输出“led thread resume success!”信息。

(5)在MobaXterm串口终端FinSH控制台中输入“threadManage delete”命令,解析自定义FinSH控制台命令后,删除LED线程,4个LED停止循环点亮,这时只有1个LED点亮,同时FinSH控制台输出“led thread delete success!”信息。使用“list_thread”命令可以看到此时LED线程已被删除。

2.1.4 小结

本节介绍了线程管理的基本概念、工作原理和管理方式。通过本节的学习,读者可掌握线程管理接口的应用。 uvzsA3l+M4++tB59xWmqGSFgvkU3ECiJ0qDV9zLX1OK2cYCuTwx+W5nFoqN6yWKe

点击中间区域
呼出菜单
上一章
目录
下一章
×