RT-Thread——线程创建概述

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

可以把线程理解成任务,假如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
    评论
RT-Thread 是一个实时操作系统,支持多线程操作。线程RT-Thread 中的基本执行单元,可以通过 RT-Thread 的 API 来创建和管理线程RT-Thread 线程创建 API 主要有以下几个: 1. rt_thread_t rt_thread_create(const char *name, void (*entry)(void *parameter), void *parameter, size_t stack_size, rt_uint8_t priority, rt_uint32_t tick); 该函数用于创建一个线程,参数如下: - name:线程的名称(必填)。 - entry:线程的入口函数(必填)。 - parameter:传递给线程入口函数的参数。 - stack_size:线程栈的大小,以字节为单位。 - priority:线程的优先级,取值范围是 0~31,数值越小优先级越高。 - tick:线程的时间片长度,以系统时钟节拍为单位。 2. void rt_thread_startup(rt_thread_t thread); 该函数用于启动一个线程,参数是线程句柄。 3. rt_thread_t rt_thread_self(void); 该函数返回当前线程的句柄。 4. rt_err_t rt_thread_delete(rt_thread_t thread); 该函数用于删除一个线程,参数是线程句柄。 5. rt_err_t rt_thread_yield(void); 该函数用于让出当前线程的时间片,让其他线程执行。 6. rt_err_t rt_thread_suspend(rt_thread_t thread); 该函数用于挂起一个线程,使其暂停执行。 7. rt_err_t rt_thread_resume(rt_thread_t thread); 该函数用于恢复一个被挂起的线程,使其继续执行。 以上是 RT-Thread 线程创建的几个基本 API,可以根据实际需求选择使用。需要注意的是,线程的优先级和时间片长度是影响线程执行顺序的重要因素,需要根据实际情况进行设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值