RT-Thread之线程的诞生与消亡史

2023-11-18

1、引言

本文基于Cotex-M内核处理器分析讨论RT-Thread中线程从创建到消亡的整个详细过程。

  • 线程的载体-控制块

    RT-Thread中是用线程控制块来描述线程实体的,在 RT-Thread 中,线程控制块由结构体 struct rt_thread 表示,线程控制块是操作系统用于管理线程 的一个数据结构,它会存放线程的一些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之 间连接用的链表结构,线程等待事件集合等 。所有对线程的操作归根结底都是对线程控制块中以上属性所对应变量的操作。

  • 线程的诞生

    线程不会自己产出,需要人为的去创建,RT-Thread提供了两种方式:使用 rt_thread_create() 创建一个动态线程,使用 rt_thread_init() 初始化一个静态线程,动态线程与 静态线程的区别是:动态线程是系统自动从动态内存堆上分配栈空间与线程句柄(初始化 heap 之后才能 使用 create 创建动态线程),静态线程是由用户分配栈空间与线程句柄 。

  • 线程的消亡

    线程的消亡分为人为删除和自然消亡。

    自然消亡:线程结束(线程入口函数返回)后,当前线程也会随之消亡。

    人为删除又分为两种情况:

    情况一:对于一些使用 rt_thread_create() 创建出来的线程,当不需要使用,或者运行出错时,我们可以使用
    rt_thread_delete()从系统中把线程完全删除掉。
    情况二:对于用 rt_thread_init() 初始化的线程,使用 rt_thread_detach() 将使线程对象在线程队列和内核对
    象管理器中被脱离(删除)。

2、线程删除细节

RT-Thread中线程删除过程分为两个步骤:

​ 第一、先将该线程从系统就绪队列中删除,再将该线程的状态更改为关闭状态,不再参与系统调度,然后挂入rt_thread_defunct 僵尸队列(资源未回收、处于关闭状态的线程队列)中。

​ 第二、空闲线程会回收被删除线程的资源。

上诉第一步的处理过程的本质是,直接(直接删除)或者间接调用rt_schedule_remove_thread()来完成上诉操作。所谓直接是指人为的调用 rt_thread_delete()或者rt_thread_detach()函数,这两个函数函数内部都调用了rt_schedule_remove_thread()函数。所谓间(自然消亡)接是指线程结束(线程入口函数返回)后,系统空闲线程 自动执行 rt_thread_exit() ,该函数中也调用了rt_schedule_remove_thread()函数。

直接删除操作比较好理解,我们重点对自然消亡的线程删除过程进行分析。通过上面描述我们只知道线程运行结束时会自动执行 rt_thread_exit() 函数,对于如何调用rt_thread_exit()的细则一开始是一头雾水。下面经过分析源码我们将拨开这层神秘的面纱。

无论是调用rt_thread_create()创建的动态或是调用rt_thread_init()创建的静态线程,内部都是通过调用_rt_thread_init()函数来完成线程创建工作的。下面我们对 _rt_thread_init()函数进行分析

static 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->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr + thread->stack_size - 4),
                                          (void *)rt_thread_exit);
……
   //省略部分  
}

_rt_thread_init() 函数内部调用了rt_hw_stack_init()函数对线程控制块进行初始化,这个也是线程创建的本质。

rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
                             rt_uint8_t *stack_addr,
                             void       *texit)
{
……
   //省略部分  
    
    /*设置函数返回地址*/
    stack_frame->exception_stack_frame.lr  = (unsigned long)texit;     /* lr */

    ……
   //省略部分  
}

对于rt_hw_stack_init函数我们重点stack_frame->exception_stack_frame.lr = (unsigned long)texit;这句代码将内部arm内部lr寄存器的值赋予了函数指针参数texit。而texit传递的是rt_thread_exit函数。由此可见rt_hw_stack_init函数返回后会执行rt_thread_exit函数。

连接寄存器 R14

R14 是连接寄存器(LR)。在一个汇编程序中,你可以把它写作 both LR 和 R14。 LR 用于 在调用子程序时存储返回地址。例如,当你在使用 BL(分支并连接, Branch and Link)指令时, 就自动填充 LR 的值。 AR

Cortex-M 内核下,c函数结束后会通过BX LR 指令自动跳转到LR寄出去中的地址中去执行指令,因此RTT中rt_hw_stack_init()函数返回后会跳转到rt_thread_exit()函数去执行,在rt_thread_exit()函数中调用rt_schedule_remove_thread()来执行上诉线程删除的第一个步骤。第一步执行完成后,系统空闲时候会进入空闲线程,空闲线程的入口函数为rt_thread_idle_entry(),此函中调用rt_thread_idle_excute()对僵尸线程资源进行回收,从而完成线程删除的最终工作。

static void rt_thread_idle_entry(void *parameter)
{
#ifdef RT_USING_IDLE_HOOK
    rt_size_t i;
#endif

    while (1)
    {

#ifdef RT_USING_IDLE_HOOK
        for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
        {
            if (idle_hook_list[i] != RT_NULL)
            {
                idle_hook_list[i]();
            }
        }
#endif

        rt_thread_idle_excute();//释放僵尸线程所占资源
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RT-Thread之线程的诞生与消亡史 的相关文章

  • Android App的工作原理

    Android App的工作原理 Android系统是基于liunx内核的 但是与传统的基于liunx的pc系统不同 用户对Android app没有绝对的掌控权 pc系统中 在应用程序的系统菜单上选择 退出 或者 关闭 之类的选项会直接杀
  • 大型项目一定用angular吗

    不一定 虽然Angular在构建大型项目方面具有优势 但选择使用何种前端框架还需要考虑多个因素 包括项目需求 团队技能 开发周期 项目规模和性能需求等 以下是一些需要考虑的因素 项目规模和复杂性 Angular 的模块化 依赖注入和组件化架
  • bootstrap label的for属性

  • Spring Boot 统一返回前端封装VO类型结果集定义

    现在大部分项目都是前后端分离的项目 为了统一管理 后端需要对数据进行封装对应的VO数据 什么是Vo我就不叙述了 这里贴出我自己的VO封装类 项目的故障码并没有定义太多 所以也没有定义枚举类型 供大家参考 import io swagger
  • Unity查看接入的Ironsource和adapter 版本号

    APPLOVINADAPTER版本号
  • vmware 开机自动启动虚拟机

    vmware开机自动启动 可以使用vmrun命令 1 首先在 我的电脑 属性 高级 环境变量 PATH 中添加vmware路径 如 C Program Files x86 VMware VMware Workstation 2 新建一个 启
  • Kafka一文懂

    初识 Kafka 什么是 Kafka Kafka 是由 Linkedin 公司开发的 它是一个分布式的 支持多分区 多副本 基于 Zookeeper 的分布式消息流平台 它同时也是一款开源的基于发布订阅模式的消息引擎系统 Kafka 的基本
  • 影响DDR5稳定性的RAS功能

    内存的稳定性 离不开RAS功能 这里的RAS Reliability Availability and Serviceability 即可靠性 可用性和可维护性的简称 RAS功能一方面可以通过调整信号规避风险 另一方面 在发生错误时及时发现
  • js常用正则表达式 匹配多个汉字、数字、英文、所有字符(附带Layui中form的表单验证)

    常用正则表达式 转自 菜鸟工具 https c runoob com front end 854 一 校验数字的表达式 数字 0 9 n位的数字 d n 至少n位的数字 d n m n位的数字 d m n 零和非零开头的数字 0 1 9 0
  • 系统部署的基本流程

    系统部署的基本流程 系统升级部署的步骤 系统升级部署的步骤 一 web后台 1 确保代码正确 配置正确 打包为war 2 登录现有web端查看部分数据正常 数据库部分表时间段数据正常 3 连接服务器 进入相应tomcat 停止tomcat
  • Vite简介

    Vite是一个快速 轻量级的前端构建工具 它可以让开发者更高效地进行前端开发 相比于其他构建工具 Vite的特点在于快速的冷启动 模块热替换和按需编译等功能 下面我们将详细探讨Vite的优势和如何使用它 什么是Vite Vite是一款基于R
  • python进阶(七):并发和多线程

    一 多线程 原文 大纲 首页 并发是一种同时执行多个任务的方式 而多线程是一种实现并发的技术 在Python中 可以使用多线程来实现并发编程 了解Python的并发和多线程对于编写高效和响应性的程序非常重要 并发 vs 并行 在讨论并发和多
  • 支持本地挂载的网盘文件列表工具AList

    什么是 Alist AList 是一个支持多存储的文件列表程序 使用 Gin 框架和 Solidjs 库 可以将常见的 18 种网盘整合在一起 并支持 WebDAV 客户端访问 之前老苏写过一篇 Alist 但此 Alist 非彼 Alis
  • Hyperledger2.0 链码安装

    文章目录 简介 package install approveformyorg commit 半自动化安装链码 简介 以Hyperldger2 0为例 链码的安装主要分为以下几部分 package 打包源代码 install 安装链码 ap
  • Embedded world conference 2015

    本文转载至 http www embedded world eu program html 一些相关的议程 Tuesday February 24 13 30 14 30 Keynote 1 Conference Keynote 09 30
  • k3服务器端的虚拟,k3服务器 客户端配置

    k3服务器 客户端配置 内容精选 换一换 选择Windows开发环境下 安装Eclipse 安装JDK 请安装JDK1 8及以上版本 Eclipse使用支持JDK1 8及以上的版本 并安装JUnit插件 若使用IBM JDK 请确保Ecli
  • 想搞清是服务器否存在内存泄漏或jvm其他方面的问题

    解决问题 想搞清是服务器否存在内存泄漏或jvm其他方面的问题 heap dump heap dump文件是一个二进制文件 它保存了某一时刻JVM堆中对象使用情况 HeapDump文件是指定时刻的Java堆栈的快照 是一种镜像文件 Heap
  • 深度学习总结(一)

    深度学习总结 一 1 经典优化算法 1 一阶迭代法 又称梯度下降法 2 二阶迭代法 牛顿法 一般在神经网络里面 L 函数就是代价函数 2 不同梯度下降法 1 经典梯度下降法 2 随机梯度下降法 随机梯度下降法可以解决经典梯度下降法数据量大
  • 代码随想录算法训练营第一天

    704 二分查找 题目链接 力扣 二分法写代码时一般是写左闭右闭和左闭右开两种类型 左闭右闭 left right 左闭右开 left right 指右边不包含right这个值 int right size 两大问题 while left
  • 全新的刷脸支付开辟一条全新发展之路

    数字化和刷脸支付的强强联合给众多商家带去希望和惊喜 崭新的2021年 这个惊喜仍然在继续 数字化经营刷脸支付 如何为创业者带去商机 2020年 是刷脸支付发展的黄金时期 它曾因为疫情跌落到谷底 却也因为疫情再次飞上云端 重拾自信 在行业巨头

随机推荐

  • form 校验多个表单

    有的时候 表单需要拆开多个 这时候就需要校验多个表单
  • Qt 学习之路:线程和 QObject

    前面两个章节我们从事件循环和线程类库两个角度阐述有关线程的问题 本章我们将深入线程间得交互 探讨线程和QObject之间的关系 在某种程度上 这才是多线程编程真正需要注意的问题 现在我们已经讨论过事件循环 我们说 每一个 Qt 应用程序至少
  • c# winform对数据库进行增删改查操作

    开发工具 sqlserver2012 visoual code 2017 打开sqlserver2012 创建一个表 表结构如下 然后打开VS2017 文件 新建 项目 Windows窗体应用 这里我就在工具箱拉取了三个button和一个显
  • VS Code+Anaconda(国内源)配置python

    一 Anaconda的介绍 为何使用 优点 二 Anaconda下载和安装 三 VS Code下载及安装 四 Anaconda更换国内源 原因及操作方法 操作方法 具体操作方法 记得看上边优秀博客 五 TensorFlow环境 配置原因及优
  • equals底层

    Equals底层实现 这篇文章有抄两个博主的东西 请不要介意 学习最重要 主要怕你们什么时候删帖看不到 谢谢 在基础类型中都重写了equals方法 但是Object中的equals的方法如果不重写就没有意义 因为源代码中equals直接用
  • Equals和HashMap的重写

    一 首先 老铁们应该先了解API中的HashCode和equals解释 1 如果两个对象相同 即用equals比较返回true 那么它们的hashCode值一定要相同 2 如果两个对象的hashCode相同 它们并不一定相同 即用equal
  • 光敏传感器简介

    光敏传感器 1 简介 光敏传感器是最常见的传感器之一 它的种类繁多 主要有 光电管 光电倍增管 光敏电阻 光敏三极管 太阳能电池 红外线传感器 紫外线传感器 光纤式光电传感器 色彩传感器 CCD和CMOS图像传感器等 光传感器是目前产量最多
  • Spring boot按日切分nohup.out日志文件的方法

    过大的日志文件维护起来存在诸多问题 所以最好是能够按日或按大小切分日志文件 下面给大家带来了Spring boot按日切分spring boot的nohup out日志文件的方法 方法如下 1 安装cronolog 2 执行以下命令启动应用
  • 完美解决umi+ProLayout 部分菜单动态的问题

    项目中用到这个框架 当然是很好用且方便的 但是实际使用的时候发现项目中限制了一些自定义内容 踩了几个坑 记录一下 动态菜单调用接口异步 页面上显示空白 解决方案 将方法放在getInitialState中查询 存在initialState里
  • 线性回归算法--拟合正弦函数

    目录 步骤 代码实现 本博客参考书籍 scikit learn机器学习 常用算法原理及编程实战 本博客源码地址 码云 步骤 生成200个在 2 2
  • Jeesite权限处理,权限分配,根据不同的用户展示不同的信息,按钮权限等

    jeesite关于权限这方面的记录或者文章很少 看官方文档又看不懂 自己的业务又需要进行权限处理 怎么办 当然问大佬了 我就记录下我的解决办法 给jeesite权限方面的文章做点贡献 我先说下我的业务逻辑 我需要实现不同公司的人登陆后台 只
  • 相似矩阵反推标签

    Background 有监督的多模态检索 supervised multi modal retrieval 中 常用 label 构造相似矩阵 S 样本集 X x i
  • vue中组件之间传递数组

    let InFo JSON stringify arr localStorage setItem array InFo 通过 JSON stringify 将数组解析成字符串 let Info JSON parse localStorage
  • gcc -c -o编译过程

    gcc编译 分步处理 一 预处理 二 编译 三 汇编 四 链接 一步到位 多模块编译 一次性编译 独立编译 C源文件到可执行文件共经历了4个过程 在使用GCC编译程序时 编译过程可以被细分为四个阶段 包括预处理 编译 汇编 链接 分步处理
  • 分析排序算法的时间复杂度和空间复杂度

    1 冒泡排序 时间复杂度 O n 2 空间复杂度 O 1 冒泡排序需要进行n 1趟冒泡 每一趟需要比较n i次 最坏情况下需要交换n 1次 故时间复杂度为O n 2 冒泡排序的空间复杂度是O 1 因为只需要使用一个临时变量即可 2 选择排序
  • 【C++】动态内存管理和泛型编程

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 C C 内存区域划分 二 常见变量存储区域 三 new
  • 程序员必知,招聘黑话大全!

    大家周末愉快 今天分享 IT 行业一些常见的招聘术语 准备参加面试的朋友一定要知道 Base base 有两层含义 对于薪资来说 base 即为你的基本薪资 假设你的薪资组成为 20k 16 签字费 股票 这个 20k 则为你的薪资 bas
  • C++中的引用

    一 引用 引用不是定义一个新的变量 而是给一个已有的变量起一个别名 类型 引用变量名 已定义过的变量名 注 1 一个变量可以有多个别名 2 引用必须初始化 3 引用只能在初始化时引用一次 不能在成为其他变量的别名 include
  • 深度神经网络在NLP的应用!

    关注后 星标 Datawhale 每日干货 每月组队学习 不错过 Datawhale干货 作者 张泽 华东师范大学 Datawhale优秀学习者 深度学习正在给自然语言处理带来巨大的变革 例如机器翻译 情感分析 问答系统等落地实践 深度学习
  • RT-Thread之线程的诞生与消亡史

    1 引言 本文基于Cotex M内核处理器分析讨论RT Thread中线程从创建到消亡的整个详细过程 线程的载体 控制块 RT Thread中是用线程控制块来描述线程实体的 在 RT Thread 中 线程控制块由结构体 struct rt