进程与线程
进程是资源分配的单位,线程是 CPU 调度的单位。面试主线:两者组成、状态流转、为什么线程轻。
进程的组成
| 部分 | 内容 |
|---|---|
| 地址空间 | 代码段、数据段、堆、栈(虚拟内存) |
| 内核数据结构 | PCB(进程控制块):pid、状态、寄存器、打开的文件 |
| 资源 | 文件描述符、信号处理器、环境变量 |
PCB 是进程的身份证:内核靠 PCB 管理进程,切换进程就是切换 PCB 和地址空间。
进程状态
进程五态: 就绪 ↔ 运行 ↔ 阻塞
- 就绪:万事俱备只差 CPU
- 运行:占用 CPU 执行
- 阻塞:等 IO 或锁,不占 CPU
面试点:阻塞不消耗 CPU,阻塞进程数多不是性能问题,就绪队列长才是。
线程
- 线程是进程内的执行流,共享地址空间和文件描述符,各有独立栈和寄存器
- 线程切换比进程切换轻:不切换地址空间(TLB 不用刷)
- 进程 = 资源容器,线程 = 容器里的执行单元
| 维度 | 进程 | 线程 |
|---|---|---|
| 资源 | 独立地址空间 | 共享地址空间 |
| 切换成本 | 高(换地址空间) | 低(只换上下文) |
| 通信 | IPC(管道/共享内存) | 直接共享变量 |
| 隔离 | 强(一个崩不影响其他) | 弱(一个崩全组崩) |
| 适用 | 隔离要求高、多核并行 | 共享状态、轻量并发 |
用户态线程与协程
- 内核只认识内核线程;用户态线程(协程)由用户库调度(见 Python 的 GIL 与 asyncio 篇)
- 协程切换不经过内核(无系统调用),比线程切换更轻
- 代价:一个阻塞的系统调用会卡住同线程的所有协程
面试追问
- 进程和线程的区别? 进程是资源分配单位(独立地址空间),线程是调度单位(共享地址空间)。切换成本进程高
- 进程有哪些状态? 就绪/运行/阻塞(加新建/终止)。阻塞不占 CPU
- 为什么线程切换更便宜? 不换地址空间,TLB 不用失效。进程切换要换页表
- PCB 是什么? 进程控制块:pid、状态、寄存器、资源列表。内核管理进程的依据
- 协程和线程? 协程是用户态调度(无内核切换),更轻;线程是内核调度。阻塞调用会卡住协程所在线程