RT-Thread——线程创建概述

本文解释了在多线程环境下,如何通过保存寄存器值来保存线程现场,特别是关注栈和寄存器在任务切换中的作用,以及rt_thread中的栈初始化过程。
摘要由CSDN通过智能技术生成

关于线程中保存现场的理解

可以把线程理解成任务,假如a和b任务差不多同时发生,先运行A任务,之后保存A的现场
再去运行B的任务,之后运行后就保存B的现场

函数本身不需要保存,但函数执行到哪需要被保存,全局变量没必要保存,因为它本身就在内核上,局部变量本身是保存在自己栈上面的,如果局部变量b在A函数里,假如A函数和B函数里的b对应的栈不冲突的话 ,是不需要保存局部变量的。我们需要保存的是中间变量,什么是中间变量呢,可以理解成原本不存在的新值,例如原来初始化了b,c两个变量(int b/c后)之后又令c=b+2,这个b+2就是中间变量,就是它原本是不存在栈中的,所以需要保存这个中间结构。
那么什么是线程呢?要回答这个问题得先了解ARM架构【详见我的上一篇文章】

我们需要注意的是如果变量是存于栈中的,那我们不用考虑对其保存现场,因为栈本身就有保存的作用,我们在执行完另一个任务后要回到这个任务时,是可以直接从栈中读取这些变量值的。所以我们把目光放向那些不在栈中的值,如寄存器的值(因为我们大多汇编指令都是对寄存器和栈进行操作,所以程序中止时往往会有许多寄存器的值没有被存入栈中),所以我们可以得出结论:保存现场其实是保存寄存器的值(SP也属于寄存器,是R13)。

保存现场的具体操作是令SP=SP-16×4,16×4是因为我们一共有16个寄存器[R0-R15(R13除外),外加一个程序状态寄存器PSR],栈之间地址相差4个比特,所以一共就是16×4。之后往里面存放我们寄存器的值。【实际下图中寄存器的顺序并不是如图所示,只是为了方便理解先排成这样的顺序】

之后就可以去执行其他任务了

创建线程的理论分析

明确一下线程三要素:

①入口函数(函数入口)

②栈 (用于保存现场,如上所述)

③线程控制块(即一个线程结构体,在任务A中止时保护现场时需要将寄存器的值存放于A之间的栈中,这个栈的地址其实是存放在线程结构体里的,当执行完B任务返回时会从线程结构体中读取A栈的地址之后恢复寄存器的值)

基于以上 我们可以去创建一个线程:首先要分配线程控制块,分配栈,建立一个入口函数(创建进程在分配时有静态分配和动态分配,而动态分配在某些安全性非常高的系统里用不了),其他参数没有三要素核心,不再赘述

[注意,句柄即我们刚刚提到的线程控制块结构体]

那么有人可能好奇我们要怎么启动一个线程?我们刚刚有提到说保存地址时要把之后要传给寄存器R0-R15的值保存起来,我们需要注意R15的值的保存很重要,因为R15是程序计数器PC,用来保存中止处将要执行的指令的地址,其实就是我们三要素里的函数入口,所以每当恢复这些寄存器值到CPU时,我们CPU会直接从R15的值即入口函数的地址处进入需要操作的部分。

而我们在启动一个线程的时候会假装暂停在第一条指令之前,目的是为了创建栈并把寄存器的值保存在栈中(所以为了完成此步CPU会分配一个属于任务自己的栈)并恢复到CPU中,之后会CPU会执行PC处也就是入口函数处的程序,这一步的目的简单地说就是让PC寄存器的值等于入口函数处的地址(PC寄存器的值为入口函数的地址),步骤是假装暂停入口函数,构造栈的内容并写入CPU。

先了解一下rt_thread的一些成员

图中的rt_hw_stack_init()的作用是为了

①虚构栈的内容,即用来存放各寄存器的值[如图中stk-=sizeof(struck stack_frame)],我们在这要注意一下就是我们刚刚提及的三要素是有被赋值的,而我们观察可以发现除此之外其他值都被赋零了

②调整SP

【图中的stack_frame其实指的是栈里放寄存器的那块区域】

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值