深入 Linux 线程机制(一):从进程到线程,理解“轻量级进程“的真相
目录
一、线程理解
1.1 感性理解线程
从操作系统教材的角度来看:
进程:由内核管理的资源分配单位,通常由代码段、数据段以及内核为其维护的数据结构组成(内核数据结构 + 代码和数据)。
线程:进程内部的一个执行流,是程序执行的基本单位。
从内核与资源管理的角度来看:
进程:资源分配的基本单位
线程:CPU 调度的基本单位
需要注意的是,教材中的定义更多是一种抽象模型,用于帮助理解操作系统的设计思想,而不是某一种固定的实现方式。
事实上,不同操作系统对“进程”和“线程”的实现差异较大,但它们背后的设计思想是一致的。
因此,在学习操作系统时,我们不能只停留在抽象概念上,而应该进一步结合具体实现来理解它们的本质。
在本章中,我们将从 Linux 操作系统的实现角度 出发,先分析进程与线程的具体实现方式,再回到概念层面进行抽象总结。
1.2 理解 Linux 下的线程
在 Linux 操作系统中,线程并不是一个与进程完全独立的新概念,而是一种 轻量化进程。
在 Linux 内核中,调度的基本单位不是 “进程” 或 “线程”,而是一个统一的结构:task_struct
1.2.1 task_struct:Linux 的调度实体
在 Linux 内核中,无论是进程还是线程,都统一由 task_struct 表示。
因此可以理解为:
CPU 调度的对象:task_struct
细节问题:CPU调度的对象为什么是 task_struct ,而不是线程?
由于操作系统的标准,Linux 确实要有线程的概念,但在内核中不一定要具体实现,而 Linux 采取的实现方案就是用轻量化进程(task_struct)来模拟实现线程的,为了让用户使用不去关注 Linux 独有的轻量化进程相关的概念,Linux 通过线程库封装了底层,让用户只需关注线程,无需关注轻量化进程。
1.2.2 进程的本质

如图所示,一个进程并不是单一的结构,而是一个资源与执行实体的组合:
- task_struct(线程)
- mm_struct(虚拟地址空间)
- 文件描述符表
- 信号处理结构等
因此从操作系统角度来看:
进程 = 资源集合 + 一个或多个 task_struct
1.2.3 线程的本质

如图所示,在 Linux 中线程同样由 task_struct 表示。
但与进程不同的是:
同一进程中的多个线程,共享同一个 mm_struct(虚拟地址空间)
因此可以得到核心结论:
Linux 中线程 = 共享资源的 task_struct 的执行流
1.2.4 Linux 为什么称线程为 “轻量级进程”
所谓“轻量”,本质体现在资源共享程度:
线程与进程在 Linux 中的区别,不是结构不同,而是共享资源的范围不同:
- 进程:拥有独立 mm_struct(地址空间隔离)
一个进程拥有一个虚拟地址空间,保证了进程之间的独立性
- 线程:共享 mm_struct(地址空间共享)
一个进程的多个线程之间可以共享同一份虚拟地址空间,保证了线程之间的共享性
1.2.5 设计思想(Linux vs Windows)
Windows 设计方式:
Windows 在进程内部显式维护线程结构(TCB),进程与线程在内核中是相对分离的模型。
- 进程:PCB
- 线程:TCB
属于“进程 + 线程分离模型”。
Linux 设计方式:
Linux 没有单独设计线程结构,而是:
复用 task_struct,用轻量化进程模拟线程
这样设计的原因是:
- 线程与进程在调度层高度相似
- 上下文切换机制几乎一致
- 复用结构可以减少内核复杂度
- 提高代码一致性与稳定性
1.2.6 小结
- CPU 在 Linux 中的调度基本单位是 task_struct
- 进程与线程的本质区别在于资源共享范围
- 线程是共享 mm_struct 的 task_struct
- 虚拟地址空间是资源隔离与共享的核心边界
1.3 线程概念的补充与理解
在 Linux 中,我们已经知道:
- CPU 调度单位是 task_struct
- 进程与线程都由 task_struct 表示
- 二者的区别在于资源是否共享
因此可以得到一个更本质的结论:
线程是进程内部的一个执行流,是 CPU 调度的基本单位。
1.3.1 进程与线程的数量关系
一个进程至少包含一个线程,该线程称为主线程。
- 只有一个线程的进程称为单线程进程
- 包含多个线程的进程称为多线程进程
1.3.2 线程的运行本质
线程的运行,本质是在共享的虚拟地址空间中独立执行。
在 Linux 中:
- 一个进程的所有线程共享同一个 mm_struct
- 共享同一套虚拟地址空间
- 通过页表映射访问物理内存
所以线程执行时:
访问的资源本质上都是通过虚拟地址空间进行访问的
1.4 线程与进程的对比
1.4.1 进程和线程的区别
| 对比维度 | 进程 | 线程(同进程内) |
|---|---|---|
| 内核角度 | 资源分配最小单位 | CPU 调度最小单位 |
| 地址空间 | 每个进程独立虚拟地址空间,相互隔离 | 共享所属进程的虚拟地址空间 |
| 上下文切换开销 | 开销大,需要修改 CR3、冲刷 TLB、Cache 大量失效 | 开销小,仅保存恢复少量线程私有寄存器,无需切换页表 |
| 数据共享 | 进程间数据共享困难,需要 IPC(管道、共享内存、socket 等)通信,开销高 | 直接读写全局变量、堆数据,共享简单高效 |
| 生命周期与依赖 | 相互独立,一个进程崩溃不会影响其他进程 | 依赖所属进程,一个线程捕获致命异常会导致整个进程崩溃 |
| 开销 | 创建、销毁开销大(需要分配地址空间、页表等资源) | 创建、销毁开销小,仅分配线程私有栈 |
| 安全性 | 进程间隔离性强,一个进程出错不会干扰其他进程 | 线程无隔离,共享资源极易出现线程安全问题 |
1.4.2 线程的优点
创建一个新线程比创建一个新进程成本更低,线程占用的资源比进程少。
原因:创建一个新线程,OS 只需要为其分配 task_struct,不需要为其分配虚拟地址空间和页表。
线程切换与进程切换相比,线程切换更低。
注:这里的线程切换,是指同一个进程的多线程进行切换。
第一点原因:线程切换无需切换虚拟地址空间,进程切换必须切换虚拟地址空间(基础原因)
底层:同一进程下所有线程共享一套虚拟地址空间与页表,CPU 中 CR3 寄存器存放当前页目录起始物理地址,线程切换不需要修改 CR3 寄存器;而进程拥有独立虚拟地址空间,进程切换必须重新赋值 CR3 完成页表切换。
第二点原因:进程上下文切换对 CPU 缓存机制的破坏程度远高于线程切换(核心原因)
底层:CPU 内置 Cache 高速缓存与 TLB 地址转换缓存:
- Cache 缓存 CPU 近期访问过的指令、数据以及对应地址标签,依托局部性原理提升访问速度;同进程线程共用虚拟地址空间,线程切换不会造成 Cache 大规模失效;进程切换更换虚拟地址空间,会导致 L1、L2 高速缓存绝大部分失效,只有少数共享内存区域、物理寻址的缓存可以复用。
- TLB 用于缓存虚拟地址到物理地址的映射,避免频繁遍历多级页表;线程切换不修改 CR3,TLB 内的地址映射可以继续复用;进程切换修改 CR3 后,TLB 中的内容会被硬件大量清空,需要重新缓存新的地址映射关系。
在 IO 等待场景下,部分线程阻塞等待 IO 数据,CPU 会调度同进程内其他线程继续执行任务,提升整体任务执行效率。
不选择多进程的原因:进程间地址空间相互独立,进程间共享数据需要借助进程间通信方式,资源共享开销高;同时进程上下文切换代价远大于线程切换。
在计算密集型场景下,可将大任务拆分,利用多核 CPU 通过多线程并行执行,缩短任务总耗时。不选用多进程的原因和 IO 密集型场景一致:进程资源共享成本高、上下文切换开销大。
补充说明:
- IO 密集型场景依靠并发即可获得性能提升:单核 CPU 下多线程交替执行,IO 阻塞时释放 CPU 给其他线程,避免 CPU 闲置;
- 计算密集型场景只有在多核 CPU 实现并行执行时才能缩短运行时间;若仅单核并发执行,多线程不仅无法提速,还会因频繁的线程切换产生额外开销,性能略有下降。
1.4.3 线程的缺点
性能损失:在一个很少 IO 且计算密集型的场景下,如果同进程创建的线程数量多于可用的 CPU 核心数,那么多线程不仅无法提速,还会因为频繁的线程切换产生额外开销,造成性能损失。
缺乏访问控制:在同一进程的多线程中,线程之间共享进程的虚拟地址空间,能看到同一份资源,如果不对要修改的资源进行保护,就会导致线程之间对同一份资源读写时产生竞争,引发数据错乱,结果异常等线程安全问题。
异常代价大:在同一进程的多线程中,如果一个线程触发异常,操作系统会先整个进程发送信号,导致争个进程内所有线程全部退出。
上述缺陷大多可以通过合理的编码设计规避风险:例如使用线程池控制线程数量减少切换开销、采用互斥同步机制保证共享资源访问安全、注册异常捕获与信号处理函数避免进程意外崩溃。
1.4.4 线程共享数据与“私有”数据
线程之间共享进程的虚拟地址空间,那么虚拟地址空间上的代码区、数据区、堆区等都是共享的,
除此之外,线程之间还共享:
例如
文件描述符表
信号的处理方式
当前工作目录
用户id和组id
线程之间的“私有数据”
例如:
线程ID
一组寄存器,线程的上下文数据
栈
errno
信号屏蔽字
调度优先级
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)