鱼宵|系列「软考架构师实战精通营(教材版)」
本篇考点权重:高频(依据近 5 年真题分布统计,供参考)

1. 本篇目标

这一篇要解决三个必考点:进程到底是什么、它的一生有哪几个状态,进程和线程差在哪、什么东西共享什么东西不共享,CPU 该把时间给谁——几种调度算法怎么算平均周转时间。学完你能默画五状态转换图、能一眼说出"阻塞不能直接跳运行"、能拿一组数据把 FCFS/SJF/时间片轮转的平均周转时间和平均等待时间都算对。上午卷这里稳定出 2~3 分,下午案例也常拿"系统响应慢"来考调度配置。

2. 对应教材

清华社《系统架构设计师教程(第 2 版)》第 2 章 计算机系统基础知识之 2.2 操作系统(进程管理、线程、调度;具体小节号与页码待核实,按官网目录页 book_09190101 归在第 2 章 2.2 节范围)。官方大纲对应条目:操作系统基本原理——进程管理、进程调度、线程(表述以 ruankao.org.cn 发布的大纲为准)。

3. 零基础开胃课

把进程想成"一桌客人点的整套菜":有菜谱(程序代码)、有备好的食材(数据)、还有一张点菜单记录这桌做到哪一步了(PCB)。线程则是这桌菜同时开动的几个厨师:他们共用同一个厨房、同一批食材(进程的代码段、数据段、打开的文件),但每人手上自己的锅、自己的进度(各自的寄存器、栈、PC)。

为什么需要"进程"这个概念?因为 CPU 只有一个(或几个),而程序有很多个。如果每个程序都从开机跑到关机,谁也别想插队。操作系统要能做到"你这会儿等一下,让别人先算",就必须给每个运行中的程序配一份"档案"——做到哪了、占了哪些内存、开了哪些文件。这份档案就是 PCB,有了它,程序才能被暂停、换出、再恢复。

一句话:进程 = 程序 + 数据 + PCB,是"能被打断、能被打断后接上"的执行单位。

4. 概念讲解

4.1 程序 vs 进程:差在"活起来"这三个字

程序是磁盘上的静态文件,一堆指令和数据,放在那儿不会自己动。进程是程序在某次执行中的实例:它被装进内存、分到了 CPU 时间、有了自己的地址空间和状态。

同一个程序可以对应多个进程。你开两个记事本窗口,磁盘上只有一份 notepad.exe,内存里却有两个进程,各有各的文档、各的光标位置。这就是"程序是剧本,进程是演出"——同一剧本可以同时有好几场。

考点:① 进程是动态的(有生命周期),程序是静态的;② 进程是资源分配的基本单位(分内存、分文件句柄);③ 一个程序可对应多个进程,一个进程也可以在执行中加载别的程序(exec)。

✅ 你该带走什么:程序是静态文件,进程是它的一次执行实例;进程动态、有生命周期、是资源分配单位,同一程序可跑出多个进程。

4.2 进程由什么组成:PCB + 程序段 + 数据段

一个进程在内存里的"身体"分三块:

  • 程序段:要执行的指令(代码),多个进程如果是同一个程序,这段可以共享(只读)。
  • 数据段:全局变量、堆、常量等。
  • PCB(进程控制块):操作系统给它建的"档案",是进程存在的唯一标志。

PCB 里通常有:进程标识(PID)、进程状态、程序计数器 PC、寄存器现场、调度信息(优先级、已用 CPU 时间)、内存管理信息(页表指针)、资源清单(打开的文件)、父子进程关系。

为什么 PCB 是"唯一标志":操作系统管理进程,靠的就是维护一张 PCB 表。PCB 建了,进程就"存在";PCB 撤了,进程就"没了"——哪怕代码还在内存里。所以考题说"进程存在的标志是 PCB",这是标准答案。

✅ 你该带走什么:进程 = 程序段 + 数据段 + PCB;PCB 是进程存在的唯一标志,状态、PC、寄存器、页表指针、打开文件都记在里面。

4.3 进程五状态:一张图定生死

进程的一生有五个状态:新建、就绪、运行、阻塞、终止。

  • 新建(New):刚被创建,PCB 建好了,还没进就绪队列。
  • 就绪(Ready):万事俱备,只差 CPU。它在就绪队列里排队等调度。
  • 运行(Running):拿到了 CPU,正在执行指令。
  • 阻塞(Blocked / 等待):跑着跑着要等某件事(I/O 完成、信号量、别的进程发消息),主动让出 CPU,去等待队列躺着。
  • 终止(Terminated):正常结束或被撤销,释放资源、回收 PCB。

转换规则(考试的命门):

从到触发原因
就绪运行被调度器选中
运行就绪时间片用完 / 被更高优先级抢占
运行阻塞请求 I/O 或等待事件(主动)
阻塞就绪I/O 完成或事件发生(被动,被别人唤醒)
运行终止进程结束

三条铁律:① 阻塞不能直接变运行,必须回就绪重新排队;② 就绪不能直接变阻塞,它还没在跑,谈不上"等事件";③ 阻塞→就绪是被动的(事件发生了),运行→阻塞是主动的(自己要去等)。

✅ 你该带走什么:五状态+四条合法箭头;阻塞→运行不存在,就绪→阻塞不存在;运行→阻塞是主动,阻塞→就绪是被动。

4.4 PCB 里到底记了什么:为什么它能"接回去"

把 PCB 想成手术记录单:病人(进程)被推进手术室(CPU),中途要换台(切走),记录单上必须写清楚"切到哪一步、用了哪些器械、输了多少血"。下次回来照着单子接着做。

PCB 关键字段:

  • 进程标识符 PID、用户标识 UID;
  • 进程状态(就绪/运行/阻塞);
  • 程序计数器 PC:下一条指令地址——这是"回到哪";
  • CPU 寄存器现场:通用寄存器、状态字——这是"手头的数";
  • 调度参数:优先级、已占用 CPU 时间、等待时间;
  • 内存信息:页表基址、段表、内存界限;
  • 资源清单:打开的文件表、占用设备;
  • 同步与通信信息:信号量、消息队列指针;
  • 链指针:挂到就绪队列或阻塞队列用。

考点:PCB 是常驻内存的(不能换出,否则管理不了);进程切换时保存/恢复的核心就是 PC 和寄存器,它们都存在 PCB 里。

✅ 你该带走什么:PCB 常驻内存;切换进程=把当前进程的 PC/寄存器存进它的 PCB,再把下一个进程 PCB 里的值装回 CPU。

4.5 进程 vs 线程:哪些共享、哪些独享

线程是进程内的一个执行流,是 CPU 调度的基本单位;进程是资源分配的基本单位。

  • 同进程的线程共享:代码段、数据段(全局变量、堆)、打开的文件与 I/O 设备、地址空间。
  • 每个线程独享:寄存器、栈(局部变量)、程序计数器 PC、线程状态。

(图 2 就是把这张表画成了图。)

为什么线程比进程"轻":切换进程要换地址空间——换页表、刷 TLB(地址转换缓存),代价大;同进程内切线程只是换寄存器和栈指针,地址空间不动,代价小得多。所以"高并发用多线程"不是因为线程更高级,而是因为切换便宜、共享数据方便。

代价:共享也意味着风险——一个线程把全局变量改坏,整个进程都遭殃;一个线程崩溃(非法访问),整个进程跟着死。进程之间是隔离的,一个崩了不影响另一个。

✅ 你该带走什么:线程共享代码段、数据段、打开的文件;独享寄存器、栈、PC。线程切换便宜因为不换地址空间;进程隔离性好因为各有地址空间。

4.6 用户级线程 vs 内核级线程

按"谁来管线程",分两种实现:

  • 用户级线程(ULT):线程的创建、调度全在用户空间的线程库(如 pthread)里做,内核只知道进程,不知道里面有几个线程。
    • 好处:切换不用进内核(不用陷入),快;一个进程可以开成千上万个线程。
    • 坏处:一个线程发起阻塞式系统调用,整个进程的所有线程都被卡住(内核认为整个进程在等);多核也用不上——内核只把这一个进程分给一个核。
  • 内核级线程(KLT):线程由内核创建和管理,每个线程都是独立的调度实体。
    • 好处:一个线程阻塞,别的线程还能跑;能真正并行在多核上。
    • 坏处:创建、切换都要进内核,开销比 ULT 大。

工业上常走混合模型(多对多):N 个用户线程映射到 M 个内核线程,兼顾灵活与并行。

考点:问"某线程阻塞会不会拖住整个进程"——ULT 会,KLT 不会;问"能不能真正利用多核"——KLT 能,纯 ULT 不能。

✅ 你该带走什么:ULT 快但一阻塞就拖全进程、上不了多核;KLT 能并行、能单独阻塞,但切换要进内核;Linux 的线程本质是共享地址空间的轻量级进程(LWP)。

4.7 进程调度:CPU 空闲时,下一个给谁

调度要解决三个问题:什么时候选(调度时机)、按什么选(调度算法)、选完怎么切(上下文切换)。

调度时机主要有:① 当前进程运行结束或终止;② 当前进程主动阻塞(等 I/O);③ 有更高优先级进程到达(抢占式);④ 时间片用完。

按"能不能抢",分两类:

  • 非抢占式(非剥夺):进程拿到 CPU 就一直跑到结束或自己阻塞,别人只能等。简单、开销小,但一个长作业会把后面全堵住。
  • 抢占式(剥夺):高优先级来了,或时间片到了,就把 CPU 收回来。响应快、公平,但要频繁切换,开销大。

评价指标三个:

  • 周转时间 = 完成时刻 − 到达时刻(从进门到出门的总时长);
  • 等待时间 = 周转时间 − 实际服务时间(纯排队的时间);
  • 响应时间 = 从提交到第一次被响应的时间(交互系统更看这个)。

✅ 你该带走什么:周转=完成−到达,等待=周转−服务,响应=到首次响应;非抢占跑到完,抢占会被收走。

4.8 FCFS:先来先服务,最公平也最笨

FCFS(First Come First Served):按到达顺序排队,先到的先上 CPU,非抢占。

优点:实现最简单、绝对公平(没有插队),不会饿死。

缺点:“护航效应”(convoy effect)——一个长作业排在前面,后面一堆短作业全得陪跑。就像超市只开一个收银台,前面那位购物车堆成山,后面只买瓶水的人也得等二十分钟。

算例(本篇演示统一用这组数据):P1 到 0 服 7、P2 到 2 服 4、P3 到 4 服 1、P4 到 5 服 4。FCFS 顺序 P1→P2→P3→P4,平均周转 8.75、平均等待 4.75(第 5 节有完整算式)。

考点:FCFS 对长作业有利、短作业不利;对 CPU 密集型和 I/O 密集型混跑时,I/O 型进程会被拖累(它跑一下就阻塞,回来又得排到队尾)。

✅ 你该带走什么:FCFS 按到达顺序、非抢占、绝对公平但护航效应明显,短作业吃亏。

4.9 SJF / SRTF:短作业优先,平均等待最短

SJF(Shortest Job First):每次从就绪队列里挑服务时间最短的跑,非抢占(一旦开跑就跑完)。它的平均等待时间在非抢占算法里是最优的——这是可以证明的结论,也是考试常问的"哪种算法平均周转时间最短"。

但有两个坑:

  • 长作业可能饿死:如果短作业源源不断到来,长作业永远排不上(饥饿)。
  • 服务时间怎么知道?现实中只能估计(按历史行为预测),估错了效果就打折。

SRTF(Shortest Remaining Time First,最短剩余时间优先):SJF 的抢占版。新进程到达时,如果它的服务时间比当前进程剩余时间还短,就抢占。它比 SJF 的平均等待更短,但切换更频繁,且同样有饥饿问题。

用同一组数据,SJF 非抢占的结果是平均周转 8.0、平均等待 4.0——比 FCFS 的 8.75/4.75 明显好,原因就是 P3(只服 1)被提前捞了出来。

✅ 你该带走什么:SJF 非抢占、平均等待最优但长作业会饿死、服务时间只能估;SRTF 是它的抢占版,按"剩余时间"比较。

4.10 优先级调度:重要的事先做,但要防饿死

优先级调度:给每个进程一个优先级,每次选优先级最高的。分抢占式(高优先级一到就抢)和非抢占式(等当前跑完)。

优先级怎么定?两类口径:

  • 静态优先级:创建时定死,简单但不够灵活;
  • 动态优先级:运行中调整,比如"等待越久优先级越高"(防饥饿),或"I/O 型进程优先级调高"(让它快去快回,把 CPU 让给计算型)。

**饥饿(starvation)**是它的老毛病:低优先级进程可能永远等不到 CPU。

解法:老化(aging)——进程每等一段时间,优先级升一级。等得够久,总能轮到。

考点:① 优先级调度不保证公平;② 老化是治饥饿的标准手段;③ 实时系统里优先级还要配"优先级反转"的处理(高优先级被低优先级持有的锁挡住,用优先级继承解决)。

✅ 你该带走什么:优先级调度分抢占/非抢占;静态定死、动态可调;饥饿用老化治;实时系统注意优先级反转。

4.11 时间片轮转 RR:人人有份,切得勤

时间片轮转(Round Robin, RR):就绪队列按 FIFO 排,每个进程最多跑一个时间片 q,用完就排到队尾。抢占式(时间片到了必被收走)。

关键参数是 q 的大小:

  • q 太大:多数进程一个片就跑完,退化成 FCFS,响应变差;
  • q 太小:切换次数暴涨,上下文切换开销吃掉大量 CPU,有效算力下降。

经验值:q 取"大多数交互请求能在一个片内完成"的量级,且切换开销应远小于 q(比如切换 0.1ms、q 取 10~100ms,开销占比 0.1%~1%)。

用同一组数据、q=4 算:P1 跑 0-4(剩 3),P2 4-8(完成),P3 8-9(完成),P1 9-12(完成),P4 12-16(完成)。平均周转 8.5、平均等待 4.5。

考点:RR 对短作业和交互型友好、响应快;对长作业不利(被切碎,完成时间拖长);q 是"响应"与"开销"的平衡旋钮。

✅ 你该带走什么:RR 一人一片、用完排队;q 太大退化 FCFS,q 太小切换开销爆炸;交互型友好、长作业吃亏。

4.12 多级反馈队列:不用猜,让进程自己"降级"

前面几种算法都要预先知道服务时间或优先级,现实里难。多级反馈队列(MLFQ) 的巧思是:不猜,用行为判断。

做法:

  1. 设多个优先级不同的队列,高优先级队列时间片短(如 8ms),低优先级队列时间片长(如 16ms、32ms)。
  2. 新进程进最高优先级队列队尾。
  3. 如果它在自己的时间片内跑完 → 结束;没用完就跑完 → 说明它是短作业/交互型,留在高优先级。
  4. 用完了时间片还没完 → 说明它吃 CPU,降一级,放进下一级队列队尾。
  5. 只有高优先级队列空了,才调度低优先级队列(抢占式:高优先级队列一有进程进来,就抢)。

效果:短作业和交互型进程一直待在高层,响应快;长作业(计算型)自动沉到底层,拿大时间片慢慢跑,切换少。不用预知服务时间,就能自动分类。

代价:实现复杂、参数多(几级队列、各级时间片、降级规则都要调),而且老进程可能被新来的短作业反复抢占(也要配老化)。

✅ 你该带走什么:MLFQ=多级队列+时间片递增+用完降级;短作业留高层响应快,长作业沉底层少切换;不用预知服务时间,但实现复杂。

4.13 响应比与 HRRN:折中的第三种思路

HRRN(Highest Response Ratio Next,最高响应比优先):非抢占,每次选响应比最高的。

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

它的妙处:短作业响应比天然高(分母小),所以短作业优先;但等得越久,响应比也越高(分子涨),长作业等到一定程度就能翻身——既照顾短作业,又不饿死长作业,正好补上 SJF 的短板。

代价:每次调度都要把队列里每个进程的响应比算一遍,开销大;而且还是要知道服务时间。

✅ 你该带走什么:响应比 R=1+等待/服务;短作业占优、老进程靠等待翻身,兼顾公平;代价是每次都要全队列算一遍。

4.14 上下文切换:看不见的性能税

上下文切换(context switch):把当前进程的"现场"存进它的 PCB,把下一个进程的现场装回 CPU。

具体动作:保存通用寄存器、PC、状态字 → 更新 PCB 状态 → 把新进程 PCB 装入 → 切换地址空间(换页表、刷 TLB) → 跳到新进程的 PC。

代价:直接开销是保存/恢复几十个寄存器(微秒级);间接开销更大——换了地址空间,TLB 和 Cache 里的内容全部失效,新进程一开始全是"冷启动",访存变慢。所以频繁切换的伤害不止"那几微秒"。

这也是"q 不能太小"和"线程切换比进程切换便宜"的物理原因:线程不换地址空间,TLB/Cache 的命中率能保住。

✅ 你该带走什么:切换=存现场+换页表+刷 TLB+跳 PC;直接开销微秒级,间接开销(Cache/TLB 冷启动)更大;线程切换不换地址空间所以便宜。

4.15 同步与互斥:为下一篇埋个伏笔

多进程/多线程并发时,会出现"共享资源被同时改"的问题。比如两个线程各自执行 count = count + 1,读-改-写三步可能交错,结果少加了一次。

解决办法:把访问共享资源的代码划成临界区(critical section),同一时刻只允许一个进程进去,靠互斥锁/信号量保证。

要正确使用临界区,得满足:互斥(同时只有一个进)、前进(没人用时想进的能进)、有限等待(不能无限期等)。

如果设计不好,就会出现死锁——两个进程各持一把锁、又都要对方的锁,谁也不放。这正是下一篇(篇 14 死锁)要拆的东西,这里先记住"互斥 → 可能死锁"这条因果。

✅ 你该带走什么:临界区要满足互斥、前进、有限等待;互斥用不好会死锁,这是篇 14 的入口。

4.16 高频陷阱清单

  1. 进程是资源分配单位,线程是调度单位——这两句别对调。
  2. 阻塞 → 运行不存在,必须经就绪。
  3. 就绪 → 阻塞不存在,它还没在跑。
  4. 运行 → 阻塞是主动(等 I/O),阻塞 → 就绪是被动(事件发生)。
  5. PCB 是进程存在的唯一标志,且常驻内存。
  6. 线程独享栈和寄存器,共享代码段/数据段/文件。
  7. 纯用户级线程上一个线程阻塞会拖住整个进程。
  8. SJF 平均等待最优(非抢占中),但会饿死长作业。
  9. RR 的时间片太大退化成 FCFS,太小切换开销爆炸。
  10. 周转时间含等待,等待时间不含服务,两个别混。

✅ 你该带走什么:这十条是选择题的高频"送命题",考前一天只扫这张单子。

5. 手把手演示

演示 1:同一组数据,三种算法各算一遍

数据(本篇统一使用):

进程到达时刻服务时间
P107
P224
P341
P454

(1)FCFS

执行顺序 P1→P2→P3→P4(按到达):

  • P1:0~7 完成,周转 7−0=7
  • P2:7~11 完成,周转 11−2=9
  • P3:11~12 完成,周转 12−4=8
  • P4:12~16 完成,周转 16−5=11

平均周转 = (7+9+8+11)/4 = 35/4 = 8.75
等待 = 周转 − 服务:0、5、7、7 → 平均 = 18/4 = 4.75
总时长 7+4+1+4 = 16,与 P4 完成时刻 16 一致,可以反查没算错。

(2)SJF(非抢占)

t=0 只有 P1 → 跑 P1(0~7)。t=7 时已到的有 P2(4)、P3(1)、P4(4),挑最短的 P3 → 7~8。然后 P2 8~12,P4 12~16。

  • P1 周转 7;P3 周转 8−4=4;P2 周转 12−2=10;P4 周转 16−5=11

平均周转 = (7+4+10+11)/4 = 32/4 = 8.0
等待 = 0、3、6、7 → 平均 = 16/4 = 4.0

比 FCFS 好 0.75,好就好在把 P3 这个"1 秒的活"提前干了。

(3)时间片轮转 q=4

t=0 队列 [P1],P1 跑 0~4(剩 3)。t=2 P2 到、t=4 P3 到,P1 用完片排到队尾 → 队列 [P2, P3, P1]。t=5 P4 到,排到末尾 → [P2, P3, P1, P4]。

  • P2 4~8 完成 → 周转 8−2=6
  • P3 8~9 完成 → 周转 9−4=5
  • P1 9~12 完成(剩 3 一次跑完)→ 周转 12−0=12
  • P4 12~16 完成 → 周转 16−5=11

平均周转 = (12+6+5+11)/4 = 34/4 = 8.5
等待 = 5、2、4、7 → 平均 = 18/4 = 4.5

三算法对比:平均周转 SJF 8.0 < RR 8.5 < FCFS 8.75。注意这个排序只对这组数据成立(RR 的 q 不同结果会变);但"SJF 在非抢占里平均等待最优"是通用结论。

演示 2:时间片选多大?

设上下文切换一次 0.1ms,进程 4 个,每个平均要跑 8ms。

q = 1ms:每个进程要跑 8 个片,4 个进程共 32 个片,切换 32 次左右,开销 32×0.1 = 3.2ms;总有效工作 32ms,开销占比 3.2/35.2 ≈ 9%——近一成的 CPU 花在切来切去上。

q = 8ms:每个进程一片跑完,切换 4 次,开销 0.4ms,占比 0.4/32.4 ≈ 1.2%——但这时退化成 FCFS,交互响应变差(后到的要等前一个跑完)。

q = 4ms:每进程两片,切换约 8 次,开销 0.8ms,占比 0.8/32.8 ≈ 2.4%,响应又能保住一半。

结论:q 的选择是"响应速度"和"切换开销"的拔河。工程经验是让切换开销控制在 1%~5%,且 q 不小于"一次典型交互所需时间"。这道算术题在案例卷里会换数字来问"调整时间片能否提升吞吐"。

演示 3:为什么"线程比进程轻"

设进程切换一次 3μs(存寄存器 1μs + 换页表刷 TLB 2μs),线程切换一次 0.5μs(只存寄存器)。

某服务每秒要切换 2000 次:

  • 用进程模型:2000 × 3μs = 6ms/s,占单核 0.6%;
  • 用线程模型:2000 × 0.5μs = 1ms/s,占 0.1%。

看似差距只有 0.5%,但真实系统里还有Cache/TLB 冷启动的间接损失——进程切换后新进程的访存几乎全部 miss,实测常比寄存器保存贵一个量级。所以"高并发用线程池而非多进程"在切换频繁的场景下优势明显,这也是案例题"某系统 QPS 上不去、上下文切换高"的标准答法。

反过来:如果目标是隔离(一个任务崩了不能拖垮别的),那就该用进程——拿切换开销换稳定性,值。

6. 真题精讲

题 1:五状态中不可能发生的转换(改编真题)

题干:进程状态转换中,下列不可能发生的是( )。
A. 就绪 → 运行 B. 运行 → 就绪 C. 阻塞 → 运行 D. 阻塞 → 就绪

答案:C。

解析:阻塞态的进程在等事件,事件发生后它只是"具备运行条件",必须回到就绪队列排队,由调度器选中才能上 CPU。C 跳过了排队,错。B 合法(时间片用完或被抢占),D 合法(I/O 完成)。这类题几乎年年变形出现,把"四条合法箭头"背死即可。

题 2:算平均周转时间(改编真题)

题干:三进程 P1(到 0,服 6)、P2(到 2,服 3)、P3(到 4,服 2),采用 FCFS,平均周转时间为( )。
A. 6.0 B. 6.67 C. 7.33 D. 8.0

答案:B。

解析:FCFS 顺序 P1(06)→P2(69)→P3(9~11)。周转时间 = 完成 − 到达:P1 6−0=6;P2 9−2=7;P3 11−4=7。平均 = (6+7+7)/3 = 20/3 ≈ 6.67。

易错点:① 把"周转"算成"服务时间"(得出 6.0,选 A);② 忘减到达时刻,把 P3 算成 11(得出 (6+7+11)/3≈8.0,选 D)。最稳的做法是先列完成时刻表,再逐个减到达时刻,最后求和除个数,不要在脑子里跳步。若同一组数据问"平均等待",则用周转减服务:0、4、5,平均 3.0。

题 3:线程共享哪些资源(改编真题)

题干:同一进程内的多个线程,共享的资源包括( )。
A. 栈指针和通用寄存器 B. 程序计数器和栈 C. 代码段、数据段和打开的文件 D. 各自的局部变量

答案:C。

解析:A、B、D 三项都是线程独享的(寄存器、PC、栈、栈上的局部变量)。C 是标准答案:代码段、数据段(全局变量/堆)、打开的文件表属于进程,线程共用。记法:“进程管资源、线程管执行”——资源归进程,所以共享;执行现场归线程,所以独享。

7. 图解

两张图:一张把五状态和箭头画全,一张把"进程和线程各拿什么"摊开。

进程五状态转换

图 1:五个状态块从左到右排开——新建、就绪、运行、终止在上一行,阻塞落在就绪正下方;箭头上的小字写着每次转换的触发原因。

读法:把它当"查表图"用。做题问"某进程此刻在等 I/O 完成,它能不能被调度",就看阻塞框——它只有一条出边(回就绪),没有直通运行的箭头,所以答案是"不能,得先回就绪排队"。问"时间片用完去哪",看运行框向左那条箭头,指向就绪。图中没有的箭头就是错的选项,这是判断状态转换题最快的办法。

进程与线程的共享与独享

图 2:一个大框表示一个进程,顶部三个蓝色胶囊是代码段、数据段、打开的文件;下面三张线程卡各自写着"独享寄存器、栈、程序计数器"。

读法:看"东西在框内哪一层"。蓝色胶囊在进程层,说明三个线程都能用;线程卡里那行字说明每人一份、互不干扰。答题时按这个层次判断:题目给的资源如果出现在进程层(代码、全局变量、文件表),答"共享";如果出现在线程层(寄存器、栈、PC),答"独享"。这张图的用处是让你在考场不用背文字,直接在脑子里"看图分层"。

8. 自测五题

  1. 进程存在的唯一标志是什么?(答:PCB)
  2. 阻塞态能被调度器直接选中运行吗?(答:不能,必须先转就绪)
  3. 线程独享哪三样?(答:寄存器、栈、程序计数器)
  4. SJF 的最主要缺点是什么?(答:长作业饥饿,且需预知服务时间)
  5. 时间片 q 设得太小会怎样?(答:上下文切换开销占比暴涨,有效算力下降)

9. 本篇题库

第 1 题(自编 · 易):进程是____的基本单位,线程是____的基本单位。
A. 调度;资源分配 B. 资源分配;调度 C. 存储;调度 D. 调度;存储
答案:B。解析:进程拥有地址空间、文件等资源,所以是资源分配单位;CPU 实际切换的是线程,所以线程是调度单位。回指:概念讲解 4.5。

第 2 题(自编 · 易):下列进程状态转换中,属于"被动"转换的是____。
A. 运行 → 阻塞 B. 阻塞 → 就绪 C. 运行 → 就绪 D. 就绪 → 运行
答案:B。解析:阻塞→就绪由外部事件(I/O 完成、信号量释放)触发,进程自己没主动做什么,所以是被动;运行→阻塞是自己请求 I/O,属主动。回指:概念讲解 4.3。

第 3 题(自编 · 中):某系统采用时间片轮转,时间片设为 100ms,而平均进程只需 20ms 就能完成。该系统最可能出现的问题是____。
A. 上下文切换过于频繁 B. 退化为先来先服务,响应变差 C. 长作业被饿死 D. 无法支持多道程序
答案:B。解析:时间片远大于典型进程的服务时间,多数进程一片就跑完,RR 的行为与 FCFS 无异,交互响应变差(后到的要等前一个整片)。回指:概念讲解 4.11 + 演示 2。

第 4 题(改编真题 · 中):四进程 P1(到 0,服 7)、P2(到 2,服 4)、P3(到 4,服 1)、P4(到 5,服 4),SJF 非抢占下平均等待时间为____。
A. 3.5 B. 4.0 C. 4.5 D. 4.75
答案:B。解析:执行序 P1(0-7)→P3(7-8)→P2(8-12)→P4(12-16)。等待:P1=0、P3=7−4=3、P2=8−2=6、P4=12−5=7,合计 16,平均 4.0。回指:演示 1。

第 5 题(自编 · 中):纯用户级线程实现(ULT)的主要缺陷是____。
A. 线程创建开销比内核级线程大 B. 一个线程阻塞会导致整个进程阻塞 C. 无法在同一进程内共享数据 D. 必须为每个线程分配独立地址空间
答案:B。解析:内核只感知进程,看不到内部线程;某线程发起阻塞系统调用时,内核认为整个进程在等,同进程其他线程全部停摆。另:ULT 也无法真正利用多核。回指:概念讲解 4.6。

第 6 题(改编真题 · 难):四进程数据同上,采用时间片轮转 q=4,P1 的周转时间为____。
A. 7 B. 9 C. 12 D. 16
答案:C。解析:P1 在 0~4 跑一片(剩 3),回队尾;P2(4-8)、P3(8-9) 之后,P1 在 9~12 跑完,完成时刻 12,周转 12−0=12。选 A 的是把 P1 当成一次跑完(那是 FCFS)。回指:演示 1(3)。

第 7 题(自编 · 难):某服务 QPS 上不去,监控显示上下文切换次数异常高、CPU 使用率高但有效吞吐低。请结合调度与切换开销给出两条优化方向并说明原理。
参考答案:① 调大时间片/减少抢占:切换开销与切换次数成正比,q 过小会让 CPU 大量时间花在存现场、换页表、刷 TLB 上;在吞吐优先的服务里适当放大 q 或改用非抢占策略可降低切换频次。② 用线程池替代"每请求一进程":线程切换不换地址空间,避免了页表切换与 TLB/Cache 冷启动的间接开销,同样并发量下切换代价更小。回指:概念讲解 4.11、4.14 + 演示 2、3。

10. 本篇技术英语

英文中文一句话解释例句/考点
process进程程序的一次执行实例,资源分配单位process control block (PCB) 进程控制块
thread线程进程内的执行流,CPU 调度单位同进程线程共享地址空间
context switch上下文切换保存/恢复执行现场切换要换页表、刷 TLB
scheduling调度决定谁用 CPU、用多久FCFS / SJF / RR / MLFQ
turnaround time周转时间完成时刻减到达时刻含等待与服务
starvation饥饿低优先级长期得不到 CPU用 aging 老化缓解
critical section临界区访问共享资源的互斥代码段需满足互斥、前进、有限等待

11. 必背清单

  1. 进程=程序段+数据段+PCB;PCB 是进程存在的唯一标志,常驻内存。
  2. 五状态:新建、就绪、运行、阻塞、终止。
  3. 合法转换:就绪→运行、运行→就绪、运行→阻塞、阻塞→就绪、运行→终止。
  4. 阻塞→运行、就绪→阻塞都不存在。
  5. 运行→阻塞是主动;阻塞→就绪是被动。
  6. 进程=资源分配单位;线程=CPU 调度单位。
  7. 线程共享代码段、数据段、打开的文件;独享寄存器、栈、PC。
  8. 线程切换不换地址空间,所以比进程切换便宜。
  9. 周转=完成−到达;等待=周转−服务;响应=到首次响应。
  10. FCFS 公平但护航效应;SJF 平均等待最优但会饿死;RR 靠 q 平衡响应与开销;MLFQ 用完降级、自动分类。
  11. 时间片太小→切换开销大;太大→退化为 FCFS。
  12. 优先级调度用"老化"防饥饿;切换代价含页表与 TLB 冷启动。

12. 速记表 + 复习计划 + 下篇预告 + 互动提问

速记表

考点一句话口诀
进程组成代码+数据+PCB
存在标志有 PCB 才算活
五状态新、就、运、阻、终
死箭头阻塞不上 CPU,就绪不去等
主动被动自己去等是主动,别人叫醒是被动
进程 vs 线程进程管资源,线程管执行
线程独享寄存器、栈、PC
切换代价换页表、刷 TLB 才叫贵
三个时间周转含等待,等待不含服务
FCFS先来先上,长作业拖死短的
SJF短的先跑,平均最优,长的饿死
RR一人一片,q 是旋钮
MLFQ用完降级,短的留高层
响应比1+等待/服务,老的能翻身

⚠️ 使用说明:这张表是复习收口用的。每句背后都有一节讲解(“死箭头”= 4.3,“换页表刷 TLB”= 4.14)。先读 4.1~4.16、算完演示 1 的三组数,再用表自查漏项。

复习计划(高频篇,2 天)

  • 第 1 天:4.1~4.6(进程与线程本体)+ 手画五状态图 + 必背 1~8
  • 第 1 天晚:4.7~4.15(调度算法)+ 演示 1 三种算法各算一遍 + 必背 9~12
  • 第 2 天:题库 7 题 + 自测五题 + 默写速记表
  • 第 7 天回看:只算 FCFS/SJF/RR 各一次,比较三个平均数

下篇预告:篇 14 进死锁——四个必要条件、银行家算法手算安全序列。今天 4.15 里那句"互斥用不好会死锁",下一篇把它彻底拆开。

互动提问:你的电脑同时开着浏览器、IDE、微信,为什么没感觉"卡"?用本篇的"时间片 + 就绪队列"解释一下它其实在每秒切多少次,评论区算算看。

Logo

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

更多推荐