Thread
线程
线程是一个基本的 CPU 执行单元,也是程序执行流的最小单位。线程也常被称为轻量级进程。
引入线程后:
| 对象 | 主要角色 |
|---|---|
| 进程 | 系统资源分配单位,例如地址空间、打开文件、I/O 资源 |
| 线程 | 处理机调度和分配单位 |
同一进程内的线程共享进程资源,例如地址空间、全局变量、打开文件等;但每个线程有自己的执行现场,例如线程 ID、程序计数器、寄存器、栈等。
线程和进程
| 角度 | 进程 | 线程 |
|---|---|---|
| 资源拥有 | 拥有独立地址空间和资源集合 | 共享所属进程资源 |
| 调度单位 | 传统系统中是调度单位 | 引入线程后成为基本调度单位 |
| 切换开销 | 切换地址空间和资源环境,开销较大 | 同进程内线程切换开销较小 |
| 通信 | 进程间地址空间隔离,需要 IPC | 同进程线程共享地址空间,通信更方便 |
| 影响范围 | 一个进程崩溃通常不直接破坏其他进程 | 一个线程错误可能破坏同进程共享数据 |
同一进程内线程切换成本较低,是因为很多资源环境不需要更换;但线程共享地址空间,也意味着共享数据更容易发生竞争,后面同步与互斥会专门处理这个问题。
用户级线程
用户级线程 ULT,User-Level Thread,由应用程序和线程库管理。操作系统内核不知道这些线程的存在。
| 问题 | 用户级线程 |
|---|---|
| 谁管理线程 | 用户态线程库 |
| 切换是否进入核心态 | 不需要 |
| 内核是否看得见 | 看不见,只看到所属进程 |
| 阻塞影响 | 一个用户级线程阻塞,可能导致整个进程阻塞 |
| 多核并行 | 同一进程内多个用户级线程不能真正同时运行在多个 CPU 核上 |
用户级线程切换快,因为不需要进入内核态。但内核只把整个进程当作调度单位:如果该进程因为一个线程执行阻塞系统调用而阻塞,对操作系统来说就是这个进程发生了阻塞,所以线程库中的其他用户级线程也可能一起停住。
内核级线程
内核级线程 KLT,Kernel-Level Thread,由操作系统内核支持和管理。内核为线程建立 TCB,Thread Control Block,即线程控制块。
| 问题 | 内核级线程 |
|---|---|
| 谁管理线程 | 操作系统内核 |
| 切换是否进入核心态 | 需要 |
| 内核是否看得见 | 看得见,内核维护 TCB |
| 阻塞影响 | 一个线程阻塞,同进程其他线程仍可运行 |
| 多核并行 | 多个线程可以在多核处理机上并行 |
内核级线程并发能力强,但线程创建、撤销、切换等工作需要内核参与,系统开销比用户级线程更大。
Important
操作系统只看得见内核级线程。因此,在支持内核级线程的系统中,真正作为处理机分配单位的是内核级线程。
用户级线程和内核级线程之间可以有不同映射关系。
| 模型 | 映射 | 优点 | 缺点 |
|---|---|---|---|
| 多对一 | 多个用户级线程映射到一个内核级线程 | 用户态切换快,管理开销小 | 一个线程阻塞可能阻塞整个进程,不能利用多核并行 |
| 一对一 | 每个用户级线程映射到一个内核级线程 | 一个线程阻塞不影响其他线程,可多核并行 | 内核级线程数量多,管理开销大 |
| 多对多 | $n$ 个用户级线程映射到 $m$ 个内核级线程,且 $n \ge m$ | 兼顾并发度和内核开销 | 实现复杂 |
多对多模型可以这样理解:用户级线程是代码逻辑的载体,内核级线程是运行机会的载体。一段线程代码只有映射到某个内核级线程并获得 CPU,才真正向前执行。
线程状态
线程也有类似进程的运行状态,例如就绪、运行、阻塞。区别在于,线程状态更强调执行流是否能获得 CPU;进程状态还涉及资源分配和地址空间等更大范围的管理。
在内核级线程系统中,调度程序通常围绕线程做调度;进程则作为线程共享资源的容器存在。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Elian's blog page!