前言

这篇文章把进程、线程相关的操作系统八股文全部梳理一遍,面试前看一遍基本够用。

从基础概念到调度算法,从上下文切换到进程通信,覆盖高频考点,每个知识点都给出了面试官最想听到的角度。


一、用户态和内核态

本质区别是 CPU 的执行权限不同。

内核态下 CPU 可以执行所有指令,访问所有硬件资源;用户态下只能执行部分指令集,无法直接操作硬件。

为什么要这么设计?三个原因:

  • 安全性:用户程序无法直接破坏硬件资源
  • 稳定性:用户态程序崩溃不会拖垮整个系统
  • 隔离性:内核和用户程序之间有明确边界,便于维护

内核态的核心操作:内存管理、进程管理、设备驱动、系统调用。


二、进程和线程

2.1 本质区别

维度 进程 线程
定义 资源分配的基本单位 任务调度和执行的基本单位
地址空间 独立 共享所属进程的地址空间
切换开销 大(需切换地址空间) 小(只切换栈和寄存器)
崩溃影响 子进程崩溃不影响其他进程 线程崩溃可能导致整个进程崩溃
通信方式 管道、消息队列、共享内存等 直接读写共享内存

2.2 为什么要有线程

用视频播放器举例。播放器有三个核心模块:读取数据、解压缩、播放画面。

单进程串行执行,读取卡住了,后面全卡死,画面不连贯。

多进程方式解决了并发问题,但进程间通信复杂,切换开销大。

线程的出现解决了这个矛盾:并发执行 + 共享地址空间,通信效率高,切换开销小。

2.3 进程、线程、协程对比

进程
├── 独立内存空间、独立堆栈
├── 内核调度
├── 切换开销:最大(需切换页表、TLB 刷新)
└── 隔离性最强

线程
├── 共享进程的堆和全局变量,独立栈
├── 内核调度
├── 切换开销:中等(只切换栈+寄存器)
└── 存在数据竞争问题,需要同步机制

协程
├── 共享堆,独立寄存器上下文和栈
├── 用户态调度,不需要内核参与
├── 切换开销:最小(无内核态切换)
└── 需要程序员显式管理调度

2.4 多线程的优劣

优势:充分利用多核 CPU,多任务并发,提高吞吐量。

劣势

  • 数据竞争,需要加锁,锁本身有开销
  • 有死锁风险
  • 消耗更多内存(每个线程都有自己的栈)

线程是不是越多越好?

不是。线程过多会导致:

  1. 频繁上下文切换,CPU 时间大量浪费在切换上
  2. 内存占用上升
  3. 锁竞争加剧,死锁概率增大

三、进程的五种状态

                    ┌─────────────────────────────────┐
                    ▼                                 │
NULL ──► 创建态 ──► 就绪态 ◄──────────────── 运行态 ──► 终止态
                    │              时间片用完 / 被抢占    │
                    │ 调度器选中                         │
                    ▼                                 ▼
                  运行态 ──────────────────────► 阻塞态
                              等待 I/O 等事件
                                                 │
                              事件完成            │
                    就绪态 ◄──────────────────────┘

关键转换:

  • 阻塞态 → 运行态不能直接转换,必须先回到就绪态,再被调度器选中
  • 就绪态 → 阻塞态不能转换,没在运行,无法发起等待

四、进程上下文切换

4.1 进程上下文有哪些

分三个层次:

用户级上下文

  • 代码段、数据段、堆、用户栈(用户空间的内存内容)

寄存器上下文

  • PC(程序计数器):下一条指令地址
  • SP(栈指针):当前栈顶
  • PSW(程序状态字):标志位,零标志/进位标志/特权位等
  • 通用寄存器:运算中间结果、函数参数、返回值

系统级上下文

  • PCB 本身(进程状态、PID、优先级)
  • 页表(内存映射)
  • 文件描述符表
  • 内核栈

寄存器上下文保存在 PCB(进程控制块)中,PCB 存在内核内存里,用户态无法直接访问。

4.2 切换流程

进程 A 运行
   │
   ▼ 触发切换(时间片用完 / 系统调用 / I/O 阻塞)
   │
   ├── 1. 保存 A 的寄存器上下文 → A 的 PCB
   ├── 2. A 的状态改为就绪或阻塞
   ├── 3. 调度器从就绪队列选出进程 B
   ├── 4. 从 B 的 PCB 恢复寄存器上下文
   └── 5. 切换地址空间(换页表,TLB 刷新)
   │
   ▼
进程 B 运行

4.3 进程切换 vs 线程切换

操作 进程切换 线程切换(同进程内)
地址空间 需要切换(刷 TLB) 不需要(共享)
寄存器 保存/恢复 保存/恢复
内核栈 切换 切换
总开销

线程切换快,本质上节省的是地址空间切换的代价(页表切换 + TLB 失效)。


五、线程切换详细过程

线程 A 运行
   │
   ▼ 调度器介入
   │
   ├── 1. 保存 A 的 CPU 上下文 → A 的 TCB(线程控制块)
   │       包括:PC、SP、PSW、通用寄存器
   ├── 2. A 的状态 Running → Ready 或 Blocked
   ├── 3. 调度器按算法选出线程 B
   ├── 4. 从 B 的 TCB 恢复上下文
   └── 5. 跳转到 B 的 PC 指向的位置继续执行
   │
   ▼
线程 B 继续运行

上下文保存在 TCB(线程控制块)中,TCB 是 OS 管理线程的数据结构,存在内核内存里。


六、三级调度

调度层级 别名 调度对象 频率
长程调度 作业调度 作业 低(从后备队列选作业进内存)
中程调度 内存调度 进程 中(换入/换出内存)
短程调度 CPU 调度 进程(现代OS是线程) 极高(毫秒级)

注意:长程调度的对象是作业,不是进程。作业经过长程调度才创建进程进入内存。


七、进程调度算法

7.1 先来先服务(FCFS)

按进入就绪队列的顺序调度,非抢占式。

  • 优点:实现简单,公平
  • 缺点:长作业先来,短作业等待时间过长

适合 CPU 繁忙型,不适合 I/O 繁忙型。

7.2 最短作业优先(SJF)

优先选运行时间最短的进程。

  • 优点:提高系统吞吐量
  • 缺点:长作业可能永远饿死

7.3 高响应比优先(HRRN)

响应比 = (等待时间 + 要求服务时间) / 要求服务时间

等待越久,响应比越高,兼顾了长作业和短作业,是 FCFS 和 SJF 的折中。

7.4 时间片轮转(RR)

每个进程分配固定时间片,用完就切换,循环执行。

时间片太短 → 切换频繁,CPU 效率低
时间片太长 → 短作业响应慢
通常设为 20ms~50ms

7.5 最高优先级(HPF)

选就绪队列中优先级最高的进程运行。

  • 静态优先级:创建时确定,不变
  • 动态优先级:随等待时间增加而提升(避免饿死)
  • 非抢占式 / 抢占式两种处理方式

缺点:低优先级进程可能永远得不到执行。


八、进程间通信(IPC)

8.1 六种方式对比

管道(Pipe)
├── 匿名管道:只能用于父子/兄弟进程,单向,内核缓存
└── 命名管道:突破亲缘限制,基于文件系统

消息队列
└── 内核中的消息链表,支持自定义数据类型,有用户态/内核态拷贝开销

共享内存(最快)
└── 直接映射到相同物理内存,零拷贝,但需要配合信号量防竞争

信号量
└── 计数器,P操作(-1)可阻塞,V操作(+1)可唤醒,解决互斥/同步

信号
└── 异步通知机制,SIGKILL/SIGSTOP 无法被捕捉或忽略

Socket
└── 跨主机通信,也支持本地通信,TCP/UDP/Unix域套接字

信号 vs 信号量(高频混淆点):

信号 信号量
用途 异步事件通知 资源计数,同步互斥
本质 软件中断 计数器
场景 Kill 进程、Ctrl+C 控制并发访问数量

共享内存为什么最快?

共享内存把同一块物理内存映射到多个进程的虚拟地址空间,进程直接读写,无需拷贝,不需要陷入内核。


九、线程间通信与同步

Linux 提供五种机制:

机制 核心用途 等待方式
互斥锁 保护临界区,互斥访问 阻塞睡眠
自旋锁 临界区极短的互斥场景 忙等(CAS 原子指令)
读写锁 读多写少的共享资源 读并发,写独占
条件变量 等待某个条件成立(配合互斥锁) 阻塞睡眠
信号量 控制资源访问数量 P操作可阻塞,V操作唤醒

互斥锁 vs 自旋锁

两者目的相同:都是保护共享资源,区别只在于抢不到锁时怎么等

互斥锁:抢不到就睡觉,让出 CPU(适合锁持有时间长的场景)
自旋锁:抢不到就原地转圈,继续占着 CPU(适合锁持有时间极短的场景)

单核 CPU 不要用自旋锁——持有锁的线程没机会运行,自旋线程会一直空转。


十、总结

面试高频考点速记

进程 vs 线程:资源分配 vs 调度执行,切换开销不同
五种状态:阻塞→就绪→运行,不能跳步
上下文切换:保存寄存器→换状态→调度→恢复→执行
三级调度:长程=作业,中程=换入换出,短程=CPU调度
进程通信:共享内存最快,管道最简单,Socket跨主机
线程同步:互斥锁睡眠等,自旋锁忙等,读写锁读并发写独占

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐