操作系统(Trochili RTOS)-线程管理与调度

Posted dengqiangjiayou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了操作系统(Trochili RTOS)-线程管理与调度相关的知识,希望对你有一定的参考价值。

操作系统(Trochili RTOS)-线程管理与调度

  • 线程是任务代码在处理器上执行的过程

  • 它是操作系统调度的基本单位,也是资源分配的基本单位

  • 线程对象由线程结构、线程栈、线程函数和相关的线程数据等部分组成

  • 线程具有多种运行状态

  • 线程状态及其所处的线程队列时匹配的

    每一个线程都会得到相应的线程储存空间,存储空间里保存了和线程相关的信息,比如线程栈深度(类似数组地址+数组长度)、线程时间片(不同的操作系统可能有所差异)、线程优先级、线程状态、线程主程序地址、线程主程序参数、线程所处队列的指针,具体看如下:
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程栈管理

​ 内核中的每一个线程都有自己的栈空间,这是在用户初始化时指定的,常见的方式是以全局数组的作为线程栈(所以在这个操作系统里其他线程也能访问当下线程的栈空间中的全局数据?),线程栈中保护的主要是线程执行的局部变量和中断相关的数据,包括:

  1. 线程被中断时处理器自动保存的寄存器数据

  2. 调用函数时,主调函数保存的寄存器数据

  3. 函数被调用时,被调函数内部的局部变量

在线程函数里不能长时间关闭中断(比如临界区代码的执行),因为多任务需要保证用户任务能被中断打断,这样操作系统才能及时响应中断。线程数据主要包括栈数据、全局数据和动态数据。栈数据编译器会确保完整和正确,但是全局数据是各个线程和内核都能访问的,所以对全局数据的访问必须是互斥的

线程队列设计

​ 每个线程的某个时刻必定属于某个线程队列。线程队列时内核用于管理线程的数据结构,它是基于线程不同的状态设置的,线程的状态和它所处的线程队列是匹配的。线程队列如下:

| 线程队列 | 作用 | 个数 |
| -------------------------------------------------------------------------------------------- |
| 线程就绪队列 | 用于保存处于就绪队列的线程结构,包括当前线程 | 1 |
| 线程阻塞队列 | 用于阻塞在IPC对象上的线程结构 | 视IPC对象个数而定 |
| 线程运行队列 | 不同的操作系统可能有也可能无 | |
| 线程挂起队列 | 同上,这里可以进行一个类比学习 | |

​ 有了线程队列方便后面线程的调度和管理

线程调度机制设计

​ Trochili RTOS的线程调度机制包括优先级抢占机制和时间片轮转机制。在不同的优先级的线程之间采用优先级抢占机制;在相同优先级线程之间采用时间片轮转机制

所以有一个问题,哪些资源是线程私有的?哪些是共享的?

以下转自:https://blog.csdn.net/weixin_44747933/article/details/111398906(看完后受益匪浅)

关于这个问题有的同学可能已经“背得”滚瓜烂熟了:“进程是操作系统分配资源的单位,线程是调度的基本单位,线程之间共享进程资源

可是你真的理解了上面最后一句话吗?到底线程之间共享了哪些进程资源,共享资源意味着什么?共享资源这种机制是如何实现的?对此如果你没有答案的话,那么这意味着你几乎很难写出能正确工作的多线程程序,同时也意味着这篇文章就是为你准备的

我的总结如下:

​ 每个线程都有一个入口函数,线程运行的本质就是函数的执行,函数运行时的信息保存在栈帧中,栈帧中保存了函数的返回值、调用其它函数的参数、该函数使用的局部变量以及该函数使用的寄存器信息,如图所示,假设函数A调用函数B:
在这里插入图片描述
由于线程运行的本质就是函数运行,函数运行时信息是保存在栈帧中的,因此每个线程都有自己独立的、私有的栈区。所以这部分栈是不共享的
在这里插入图片描述
同时函数运行时需要额外的寄存器来保存一些信息,像部分局部变量之类,这些寄存器也是线程私有的,一个线程不可能访问到另一个线程的这类寄存器信息

从上面的讨论中我们知道,到目前为止,所属线程的栈区、程序计数器、栈指针以及函数运行使用的寄存器是线程私有的

以上这些信息有一个统一的名字,就是线程上下文,thread context

我们也说过操作系统调度线程需要随时中断线程的运行并且需要线程被暂停后可以继续运行,操作系统之所以能实现这一点,依靠的就是线程上下文信息

讨论完线程私有空间,下面是线程间共享资源:

这其实就是进程地址空间的样子,也就是说线程共享进程地址空间中除线程上下文信息中的所有内容,意思就是说线程可以直接读取这些内容

下面分别概括一下这些区域:

代码区:

​ 代码区存放的就是我们写的代码,准确的说是编译后的可执行机器码。线程之间共享代码区,这就意味着程序中的任何一个函数都可以放到线程中去执行,不存在某个函数只能被特定线程执行的情况

数据区:

​ 数据区存放的是全局变量,数据区中的全局变量有且仅有一个实例,所有的线程都可以访问到该全局变量。值得注意的是,定义在函数体内的 static变量也是存放在数据区(应该也就是静态区),这类变量在函数执行完后,还可以存在静态区而不被销毁,故这个变量对每一个线程来说也都是可以访问的

堆区:

​ 即用malloc/new申请得到的动态内存,只要知道变量的地址,也就是指针,任何一个线程都可以访问指针指向的数据,因此堆区也是线程共享的属于进程的资源

每个进程的资源是不共享的,但是每个进程下的线程的资源有些可以共享有些不能共享,正如上面的总结。

以上是关于操作系统(Trochili RTOS)-线程管理与调度的主要内容,如果未能解决你的问题,请参考以下文章

操作系统(Trochili RTOS)-线程管理与调度

ARM官方《CMSIS-RTOS教程》之线程Threads

Zephyr RTOS -- 线程简介

Zephyr RTOS -- 线程简介

RTOS基础之线程间同步

CMSIS-RTOS 时间管理之时间延迟Time Delay