进程和线程
进程(Process)是程序运行的实例,即软件的执行副本;线程(Thread)是轻量级进程(Light Weighted Process),是程序执行的基本单位。进程是资源分配的基本单位,线程是 CPU 调度的基本单位。
资源分配
进程需分配三类核心资源:
- 计算资源(CPU):通过调度分配时间片段;
- 内存资源:独立的虚拟地址空间;
- 文件资源:打开的文件、I/O 设备等。
早期 OS 无线程,三类资源全部分配给进程,进程间通过管道等通信。但同一应用常有多个必须"同时进行"的行为(图形渲染、网络、响应用户输入),需将执行单位下沉——仅分配 CPU 资源的执行单元称为线程。
分时与调度
CPU 核心数少(几个到几十个)而进程/线程数多(几十到几百),因此通过分时轮流执行:每个执行单位获得一个时间片段,用尽后挂起、轮到下一个。现代 OS 直接调度线程。


状态转换
进程/线程经历三个基本状态:
- 就绪(Ready):创建后进入排队;
- 运行(Running):轮到执行;
- 阻塞(Block):等待磁盘/打印机等 I/O 时自行进入,待中断通知后回到就绪。




就绪态不能直接转阻塞(排队中无法触发 I/O 读取);阻塞态收到数据后需重新排队,不能直接回运行态。
进程与线程的表示
OS 在内存中维护进程表与线程表(常驻内核)。

进程表包含:
- 描述信息:PID、名称、所属用户;
- 资源信息:虚拟内存映射、拥有的文件与 I/O 设备;
- 内存布局:进程地址空间分段(代码段、数据段、堆、栈等)。

线程表包含 ThreadID、执行状态、优先级、程序计数器(PC)与所有寄存器的值——因线程共用 CPU、频繁切换,需保存/恢复这些上下文。
用户级线程与内核级线程存在映射关系(如 n-m 多对多)。内核维护内核级线程表;用户级线程执行时才借用内核线程(线程池模式),执行完不销毁、等待下一个任务。
隔离方案
进程间分配彼此完全隔离的地址空间:即便访问相同虚拟地址,物理地址也不同(如 A、B 小区的 808 不是同一套房)。正常情况进程 A 无法访问进程 B 内存,除非利用漏洞或进程间通信手段。

同一进程的多个线程共享该进程的内存资源,仅被分配执行资源。
切换
现代 OS 只有线程切换。每次切换:
- OS 向 CPU 发中断信号,停止当前线程;
- CPU 立即停止,尚未保存自身状态;
- OS 接管,用底层程序(汇编)保存寄存器状态;
- 执行调度程序,选定下一线程;
- 恢复该线程寄存器状态后执行。



状态保存/恢复可用栈:中断时压栈关键数据(寄存器),恢复时出栈。
多核
多核系统中可并行执行与核数相同的线程。并发(concurrent)指一段时间内看上去同时执行(不要求多核);并行(parallel)指绝对同时执行(要求多核)。OS 的保存/恢复能力使线程可在多核间迁移。

创建进程/线程的 API
- fork:创建当前进程的克隆,新进程状态与原进程一致,但拥有独立地址空间。连续多个
fork会指数级生成进程(n 次 fork 产生 (2^n) 个执行流)。 - exec 类 API:启动全新程序。
- 语言级线程 API:Java 的
Thread类、Go 的 goroutine(轻量级线程)等。

进程开销为何大于线程
创建进程自然创建主线程。进程需划分完整内存空间、做大量初始化(分段:栈、堆、代码段等);线程只需确定 PC 与寄存器值、分配一个执行栈,且同进程多线程可复用堆栈。因此创建进程更慢、内存开销更大。频繁处理请求等场景应优先用线程而非进程。
小结
进程承接存储资源、线程承接计算资源,进程包含线程并实现内存隔离。线程切换通过保存/恢复寄存器完成;多核下可并行。计算密集型任务进程开销不可忽略,应倾向多线程或 fork 复用。