Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
2024-RSOC
夏令营
【2024——ROSC】线程的学习分享
发布于 2024-07-24 21:13:09 浏览:1050
订阅该版
[tocm] # rtthread——线程 ## 线程控制块 在 RT-Thread 操作系统中,线程控制块是操作系统用于管理线程的一个数据结构。它会存放线 程的一些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之间连接用的链表结 构,线程等待事件集合等。 线程控制块由结构体 struct rt_thread 定义并形成线程内核对象,再链接到内核对象容器中进行 管理。 ## 线程的继承关系 - 在RT-Thread实时操作系统(RTOS)中,线程的继承关系主要涉及到线程的优先级继承和资源继承。 ### 1. 线程优先级继承 在RT-Thread中,线程的优先级是一个重要的调度参数,决定了线程在系统中获得CPU资源的优先级。通常情况下,新创建的线程的优先级可以通过以下方式继承: - **显式继承**:新线程可以显式地从父线程的优先级继承。这意味着如果在创建新线程时未指定优先级,则新线程会自动继承创建它的线程的优先级。 - **隐式继承**:在某些情况下,线程创建函数可能会使用默认的优先级或者从线程池中选择一个合适的优先级来创建新线程。 例如,使用RT-Thread的 `rt_thread_create` 函数创建线程时,可以通过指定 `priority` 参数来设置新线程的优先级。如果 `priority` 为 `RT_THREAD_PRIORITY_MAX` 或 `RT_THREAD_PRIORITY_MIN`,则可能会隐式继承父线程的优先级或默认优先级。 ### 2. 资源继承 除了优先级,RT-Thread中的线程还可以继承其他资源和属性,例如: - **资源限制**:父线程可能会设置某些资源限制,例如堆栈大小或者线程可用的内存大小,新线程可以继承这些限制。 - **调度器属性**:RT-Thread中,线程的调度属性可以影响其调度行为,例如是否使用抢占式调度或者固定优先级调度。新线程可能会继承父线程的调度器属性,以保持一致的调度行为。 ## 线程属性 ### 线程栈 RT-Thread 线程具有独立的栈,当进行线程切换时,会将当前线程的上下文存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。 线程栈还用来存放函数中的局部变量:函数中的局部变量从线程栈空间中申请;函数中局部变量初始时从寄存器中分配(ARM 架构),当这个函数再调用另一个函数时,这些局部变量将放入栈中。 对于线程第一次运行,可以以手工的方式构造这个上下文来设置一些初始的环境:入口函数(PC 寄存器)、入口参数(R0 寄存器)、返回位置(LR 寄存器)、当前机器运行状态(CPSR 寄存器)。 ### 线程状态 RT-Thread系统中的每一线程都有多种运行状态。系统初始化完成后,创建的线程就可以在系统中竞争一定的资源,由内核进行调度。 线程状态通常分为以下五种: 初始态(RT_THREAD_INIT):创建线程的时候会将线程的状态设置为初始态。 就绪态(RT_THREAD_READY):该线程在就绪列表中,就绪的线程已经具备执行的能力,只等待CPU。 运行态(RT_THREAD_RUNNING):该线程正在执行,此时它占用处理器。 挂起态(RT_THREAD_SUSPEND):如果线程当前正在等待某个时序或外部中断,我们就说这个线程处于挂起状态,该线程不在就绪列表中。包含线程被挂起、线程被延时、线程正在等待信号量、读写队列或者等待读写事件等。 关闭态(RT_THREAD_CLOSE):该线程运行结束,等待系统回收资源。 ![image-20240724120812704](C:\Users\27545\AppData\Roaming\Typora\typora-user-images\image-20240724120812704.png) ### 优先级 RT-Thread 线程的优先级是表示线程被调度的优先程度。每个线程都具有优先级,线程越重要,赋予的优先级就应越高,线程被调度的可能才会越大。 RT-Thread 最大支持256 个线程优先级(0~255),数值越小的优先级越高,0 为最高优先级。在一些资源比较紧张的系统中,可以根据实际情况选择只支持8 个或32 个优先级的系统配置;对于ARM Cortex-M系列,普遍采用32 个优先级。最低优先级默认分配给空闲线程使用,用户一般不使用。在系统中,当有比当前线程优先级更高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理器运行。 ### 时间片 每个线程都需要配置时间片,但时间片仅对优先级相同的就绪态线程有效。系 统对优先级相同的就绪态线程采用时间片轮转的调度方式进行调度时,时间片起到 约束线程单次运行时长的作用,其单位是一个系统节拍(OSTick)。 ### 线程入口函数 + 线程所实现的功能由入口函数实现。 + 函数格式:void (*entry)(void* parameter) • 函数要求:要有让出 CPU 的动作(让出CPU:如 rt_thread_mdelay() ) ### 常见线程的错误码 ![image-20240724121102522](C:\Users\27545\AppData\Roaming\Typora\typora-user-images\image-20240724121102522.png) ## 系统线程 ### 空闲线程 空闲线程是系统创建的最低优先级的线程 ,线程状态永远为就绪态。 当系统中无其他就绪 态线程存在时 ,调度器将调度到空闲线程。 它通常是一个死循环 ,且永远不能被挂起。 空闲线程在 RT-Thread 中有着特殊的用途: + 若某线程运行完毕,系统将自动删除线程: 自动执行 rt_thread_exit() 函数,先将该线程 从系统就绪队列中删除 ,再将该线程的状态更改为关闭状态 ,不再参与系统调度 ,然后挂入 rt_thread_defunct 的僵尸队列(资源未回收、处于关闭状态的线程队列) 中 ,最后由空闲线 程回收被删除线程的资源。 + 空闲线程也提供了接口来运行用户设置的钩子函数,在空闲线程运行时会调用该钩子函 系统线程-空闲线程 数,适合钩入功耗管理、看门狗喂狗等工作。 ### 主线程 RT-Thread 中的 main() 函数是一个线程,称为主线程。 在系统启动时 ,系统会创建 main 线程 ,它的入口函数为 main_thread_entry() ,用户的 应用入口函数 main()就是从这里真正开始的 ,系统调度器启动后 , main 线程就开始运行, 过程如下图 ,用户可以在 main() 函数里添加自己的应用程序初始化代码。 ![image-20240724121359714](C:\Users\27545\AppData\Roaming\Typora\typora-user-images\image-20240724121359714.png) ## 线程管理API ### 线程初始化 线程的初始化可以使用下面的函数接口完成,来初始化静态线程对象: `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: 线程的优先级。优先级范围根据系统配置情况(rtconfig.h 中的RT_THREAD_PRIORITY_MAX 宏定义),如果支持的 是 256 级优先级,那么范围是从 0 ~ 255,数值越小优先级越高,0 代表最高优先级。 tick : 线程的时间片大小。时间片(tick)的单位是操作系统的时钟节拍。当系统中存在相同优先级线程时,这个参数指定 线程一次调度能够运行的最大时间长度。这个时间片运行结束时,调度器自动选择下一个就绪态的同优先级线程进行 运行。 ### 线程创建 可以使用下面的函数接口完成,来初始化静态线程对象: `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: 线程的优先级。优先级范围根据系统配置情况(rtconfig.h 中的RT_THREAD_PRIORITY_MAX 宏定义),如果支持的 是 256 级优先级,那么范围是从 0 ~ 255,数值越小优先级越高,0 代表最高优先级。 tick : 线程的时间片大小。时间片(tick)的单位是操作系统的时钟节拍。当系统中存在相同优先级线程时,这个参数指定 线程一次调度能够运行的最大时间长度。这个时间片运行结束时,调度器自动选择下一个就绪态的同优先级线程进行 运行。 ### 线程启动 rt_err_t rt_thread_startup(rt_thread_t thread) 创建(初始化) 的线程状态处于初始状态 ,并未进入就绪线程的调度队列 ,可以在线程初始化 / 创建成功后调用下面的函数接口让该线程进入就绪态。 当调用这个函数时 ,将把线程的状态更改为就绪状态 ,并放到相应优先级队列中等待调度。如果 新启动的线程优先级比当前线程优先级高 ,将立刻切换到这个线程。 ### 删除(脱离)线程 #### 1.使用rt_thread_init()初始化线程,需要使用rt_thread_detach将使线程对象在线程队列和内核对象管理器中被脱离。 rt_err_t rt_thread_detach (rt_thread_t thread) thread :线程句柄 #### 2 对于一些使用rt_thread_create() 创建出来的线程,当不需要使用,或者运行出错时,我们可以使用下面的函数接口来从系统中把线程完全删除掉: rt_err_t rt_thread_delete(rt_thread_t thread) thread : 要删除的线程句柄 ### 线程延时 抢占式系统线程在不使用CPU时需要让出CPU的使用权 ,让其他线程得以运行。 这里可以使用线程延时或睡眠来实现。 使用以下API让运行的当前线程 延迟/休眠 一段时间,在指定的时间到达后重新运行: rt_err_t rt_thread_sleep(rt_tick_t tick); 时钟节拍为单位 rt_err_t rt_thread_dealy(rt_tick_t tick);时钟节拍为单位 rt_err_t rt_thread_mdelay(rt_Uint32_t ms);以毫秒为单位
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
才淇高理
这家伙很懒,什么也没写!
文章
6
回答
1
被采纳
0
关注TA
发私信
相关文章
1
2024RT-Thread操作系统
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部