进程是操作系统资源分配的基本单位。本文从 Linux 视角整理进程的创建(fork/exec)、状态机、PCB 结构,以及进程/线程上下文切换的机制与开销。
进程生命周期经历多个状态,核心状态如下:
状态迁移由调度器与事件驱动:就绪→运行(调度)、运行→就绪(时间片到/被抢占)、运行→阻塞(等待 I/O)、阻塞→就绪(I/O 完成)。
Linux 创建进程用两个系统调用组合:
pid_t pid = fork();
if (pid == 0) {
// 子进程
} else {
// 父进程,pid 为子进程 pid
}fork 创建一个几乎完全复制父进程的子进程:复制 PCB、页表、文件描述符等。execve("/bin/ls", argv, envp);exec 用新程序替换当前进程的映像(代码、数据、堆栈),PID 不变。fork + exec:父进程 fork 出子进程,子进程 exec 加载新程序。init/systemd 是所有进程的祖先。wait 回收其 PCB,残留一条 PCB。init 收养。每个进程在内核中有一个 PCB(Process Control Block,Linux 中为 task_struct),记录:
PCB 是内核管理进程的"档案",所有进程的 PCB 由内核统一管理(Linux 的 task list)。
当调度器决定从进程 A 切换到进程 B 时,发生上下文切换:
上下文切换的过程:
开销:
上下文切换是"昂贵"的操作,因此现代系统倾向减少切换频率或用线程(线程切换共享地址空间,无需切页表,开销小于进程切换)。
| 维度 | 进程切换 | 线程切换 |
|---|---|---|
| 地址空间 | 需切换页表,TLB 失效 | 同进程内共享,不切页表 |
| 资源 | 文件、信号等独立 | 共享 |
| 开销 | 大 | 较小 |
| 触发 | 进程级调度 | 线程级调度 |
同一进程内的线程切换因无需切换地址空间而更快;跨进程的线程切换开销则与进程切换相当。
调度器维护就绪队列,按优先级与虚拟运行时间选择下一个运行实体。长期以来的 CFS 调度器以红黑树组织就绪任务;自内核 6.6 起,CFS 已被同样基于虚拟时间的 EEVDF 调度器取代(截至 2026-09 的主流内核)。进程/线程在 Linux 中统称为 task,调度单位是 task_struct。