2024.07.01:操作系统线程学习笔记
第7节 线程
- 7.1 线程的基本概念
- 7.1.1 单线程地址空间 vs 多线程地址空间
- 7.2 线程的状态与转换(照搬进程设计)
- 7.2.1 线程的3种基本状态
- 7.3 线程管理中的数据结构
- 7.3.1 线程的用户栈
- 7.3.2 线程的内核栈
- 7.4 线程的控制
- 7.4.1 线程的创建
- 7.4.2 线程的终止
- 7.5 线程的实现方式(难点)
- 7.5.1 用户级线程ULT(用户空间实现的线程)
- 7.5.2 内核支持线程KST==内核级线程KLT(内核空间实现的线程)
- 7.5.3 多线程模型
7.1 线程的基本概念
线程:其实就是在我们引入进程的基础上之后,再对进程进行进一步的划分
- 一个进程往往只有一个执行点,也就是说这个进程我们就是从他最开始的那条指令开始执行,中间可能经历阻塞,再次运行等停顿,但都还是一个进程单位
- 当我们将进程细分划为线程,一个多线程的进程就会有多个执行点。(一个执行点到下一个执行点的过程就可以被称为一个线程)
进程划分线程只是把一个进程要执行的所有的任务又给细分成了多个线程,这些线程也是可以独立的去调度的,所以谁在谁之前上处理机都不一定,因为他们已经完成成为了进程内部一个新的可以独立去调度的单位,每一个线程就类似一个新的独立的进程,只是他比进程的规模还要小
- 对于进程来说,每个进程都有它独立的地址空间。但是同属于一个进程的线程们会共享进程的地址空间,也就是一个进程内的线程是没有自己独立的地址空间的
7.1.1 单线程地址空间 vs 多线程地址空间
注意:单线程的地址空间此处为什么没有加那个内核区域
linux操作系统,它的一个进程映像,或者说这个进程的地址空间,它是包含了高地址这一部分的内核区。并不是说这个操作系统的内核去代码在这个进程里面。只是对于这个进程来说,他知道这个地址范围内会映射到操作系统的内核代码上去,内核不属于进程。所以对于进程来说,虽然他的进程地址空间有这么大,但是只有下面的部分是他可用的,上面是他知道他存在但不属于他的进程,只是能映射到内核上去
每个进程都有自己独立的栈,并且线程之间没有做保护措施,每个线程的栈可以被其他线程读写甚至清除,由一个线程打开的文件也可以被其他线程读写。
线程只是作为独立调度和分派的单位,而进程此时只会作为拥有资源的单位。也就是说分配资源的时候,系统还是以进程为基本单位,而不会给线程分配太多的资源,当运行和调度的时候,就会从调度进程转变为调度进程。因而线程没有独立的地址空间,也没有掌握资源,完全依附于进程
7.2 线程的状态与转换(照搬进程设计)
7.2.1 线程的3种基本状态
就绪态(只缺CPU这一个资源):线程已具备执行条件,只差CPU
执行态(执行回到就绪原因就是CPU已经不在他上面了):线程获得CPU并且正在运行
阻塞态:线程在执行过程种因某件事而受阻,处于暂停状态
7.3 线程管理中的数据结构
为了便于系统去描述和管理线程,操作操作为每个线程定义了一个数据结构ThreadCB(线程控制块)
对于一个线程来说,他是有两个栈的:用户栈和内核栈
区分线程的内核栈和用户栈的原因:每个进程运行时都持有上下文,用于保证并行性。为了保证内核和用户态隔离,陷入内核不影响用户态,所以使用了不同的栈
7.3.1 线程的用户栈
7.3.2 线程的内核栈
7.4 线程的控制
7.4.1 线程的创建
用户程序在启动时,通常只有一个初始化线程在执行,它利用一个线程创建函数来创建新线程,并返回一个线程标识符
7.4.2 线程的终止
- 终止线程通过调用相应的函数执行终止操作,大多数操作系统中,线程被终止后不会立即释放它所占有的所有资源
- 只有当进程中的其他线程执行了分离函数后,被终止的线程才会与资源分离,此时的资源才能被其他线程利用。
- 已被终止但尚未释放资源的线程,仍可被需要它的线程所调用以恢复运行
7.5 线程的实现方式(难点)
区分点就是线程控制块在内核空间还是用户空间
7.5.1 用户级线程ULT(用户空间实现的线程)
在早期的操作系统中,它往往只支持用户级线程的,也就是整个线程的实现是放在用户空间的,由用户空间去管理的。对于内核来说,它只能看到这一个进程,它就会以为这是一个单线程的进程
把整个线程实现部分放在用户空间中,内核看到的就是一个单线程进程
用户级线程的优势
- 线程管理是在用户空间去实现的,因此这个线程切换也是在用户空间用户空间直接就实现了,它无需进行模式的切换(CPU工作模式的切换,也就是内核态和用户态之间的切换)
- 每个进程可以选择自己专用的调度算法,对自己内部的线程进行调度和管理
- ULT的实现和操作系统的内核是无关的,所以这个ULT管理的代码会显式出现在用户程序中,所以ULT可以在不支持线程机制的操作系统平台中实现的
用户级线程的劣势
- 内核只能识别一个进程,对于内核空间来说,它感知不到这些用户级线程,然而进程的调度是由内核来完成的,当我给这样一个进程去分配CPU的时候,对于内核来说,他只能看到用户空间有一整个进程,那他就会给整个进程去分配CPU资源,看不到里面有很多个线程。因此调度的对象是整个用户进程,每次只能给整个进程分配CPU,进程中只有一个线程能执行,无法发挥多处理器系统优势
- 进程中的某个线程发起系统调用,会导致进程中的所有进程全部被阻塞
7.5.2 内核支持线程KST==内核级线程KLT(内核空间实现的线程)
在内核的支持下去运行的线程
发展到现在,操作系统的内核就已经可以感知到这些线程了。因此,内核级线程它的撤销或者等等管理调度全部都是由操作系统内核去完成的
内核级线程的优势
- 内核可识别到内核级线程,因此调度的对象是内核级线程,在多处理机系统中,每次可以给不同的内核级线程分配CPU,提高并行度
- 如果用户进程中的一个线程被阻塞,内核可以调度该进程内的其他线程上处理机,或者调度其他进程的线程
内核级线程的劣势
- 每次线程切换都需要CPU变态,开销比较大
- TCB存放在内核空间中,内存占用较大
7.5.3 多线程模型
同时支持ULT和KST的操作系统,如何去实现,如何去确定这个用户级线程和内核级线程之间的映射关系