☰
操作系统期末复习:聚焦PV操作、银行家算法与页面置换拿分模板
2026/10/15 8:55:17 网站建设 项目流程

简介:操作系统期末复习是一项系统工程。这份面向山东大学学生的期末复习笔记,以PDF文档形式系统梳理了操作系统课程的核心考点,包括操作系统概念与功能、系统结构、进程管理、进程状态转换、并发并行与共享、用户与内核模式、操作系统的三类结构设计等模块,并配有U1导论、U2操作系统结构、U3进程等章节的复习重点提示,适合考前集中梳理与查漏补缺。资源包共1个PDF文件,压缩后约2.91MB,内容结构清晰,便于打印或导入平板批注复习。目前已吸引973人次学习浏览,是该校操作系统课程期末备考的实用参考资料。该笔记在进程部分重点展开,涵盖进程与程序的区别、进程组成、状态转换时机(运行—等待—就绪—运行)、PCB、进程调度队列、父子进程关系、终止情形、共享内存与消息传递两种通信方式等高频考点,能帮助读者快速建立操作系统知识框架,提高复习效率。

1. 操作系统期末复习:先承认这课考的是「算」不是「背」

操作系统期末复习的最大误区,是把这门课当成文科来背。概念背了五遍,信号量、死锁、页面置换说得头头是道,结果卷子发下来,第一道 PV 操作题就卡了半小时——这不是个别现象,是这门课的考试方式决定的。以某高校操作系统课程为例,期末卷面里纯记忆题通常只占三到四成,剩下的大头是计算题、算法设计题和系统调用分析题。换句话说,复习的主线应该放在「手里能算出来、能写出来」的东西上,而不是「嘴里能说出来」。这篇笔记就按这个思路,把考点优先级、必考题型模板、Linux 实操验证和常见扣分点一次讲完,适合考前两到三周开始动手的读者照着执行。

2. 考点优先级拆解:把整本教材缩成一张能执行的复习表

2.1 三层过滤:从大纲、真题和实验里圈出真正的考点

操作系统教材动辄四五百页,逐页看一遍既不现实也没必要。常见的做法是做三层过滤:第一层是教学大纲和老师划的重点,这一层告诉你「考什么范围」;第二层是近三年的期末真题,这一层告诉你「范围里哪些知识点真的被考过、以什么形式考」;第三层是课程实验,这一层最容易被忽略——实验里做过的系统调用、进程同步、页面置换模拟,往往就是大题的原型。

我一般会把三层信息汇总到一张表里,横轴是章节,纵轴是题型,然后给每个知识点标上「必考 / 常考 / 选考 / 不考」四个优先级。比如进程管理里的 PV 操作和银行家算法、内存管理里的页面置换算法、文件管理里的索引节点与目录结构,这几块在多数高校的卷面上都是必考级;而设备管理里的 SPOOLing 技术细节、磁盘调度算法,属于常考但分值不高的计算题;至于一些偏理论的历史演进内容,按选考处理,时间不够就只看结论。

2.2 把考点翻译成题型:复习表的列应该是什么

很多复习计划表只有「章节 + 知识点」,这种表的问题在于它没法指导做题。我建议把表的列改成「章节 / 考点 / 题型 / 优先级 / 对应实验」,因为同样的知识点在不同题型下复习方式完全不同。比如说「进程同步」这一行,考点写「生产者-消费者、读者-写者」,题型写「信号量程序设计大题」,优先级必考,对应实验是「用系统调用或 C 语言模拟多进程同步」。这样一来,复习到这一行的时候,你脑子里想的是「我要会写一段完整的 PV 操作代码」,而不是「我好像记得信号量这个概念」。

下面给一张参考模板,具体考点可以按手头教材替换:

章节考点题型优先级对应实验
进程管理PV 操作、生产者-消费者程序设计大题必考多进程同步模拟
进程管理银行家算法、死锁检测计算与判断必考资源分配模拟
内存管理页面置换算法(OPT/FIFO/LRU)计算题必考页面置换模拟
内存管理分段分页、地址转换计算题常考无
文件管理索引节点、混合索引计算与简答常考文件系统设计
设备管理磁盘调度(SSTF/SCAN)计算题常考无

2.3 时间分配:按题型而不是按章节排计划

按章节复习有个隐蔽的问题:章节之间是平铺的,你会本能地在每个章节上花差不多的时间,但分值分布根本不是均匀的。把考点翻译成题型之后,时间分配就有了依据。我的习惯是:PV 操作和页面置换各占两到三个晚上,银行家算法一个晚上,地址转换和磁盘调度各一个晚上,概念简答集中在考前两天用背诵稿突击。这样算下来,核心计算题占据大概六成复习时间,正好对应卷面上六成的分值。

另外一个容易被忽视的点是:真题不要留到考前最后一天才做。正确做法是复习完一个题型模块,立刻拿真题里对应的那一两道题验证。比如今晚练完 PV 操作模板,就翻开真题把历年所有 PV 大题做一遍,哪怕都是同一道题的变体。这样做的好处是,你能在最短时间内发现「模板会了但题目读不懂」这类问题,而不是等上了考场才发现。

3. 必考计算与算法题:PV操作、银行家算法、页面置换的拿分模板

3.1 PV操作大题:从信号量语义到四步解题模板

PV 操作题是操作系统期末卷面上最常见的丢分点,翻车原因几乎一样:信号量初值乱设、P/V 顺序颠倒、缓冲区边界没处理。先把信号量的语义理清:信号量是一个非负整数,P 操作(wait)是请求资源,信号量减一,小于零则阻塞;V 操作(signal)是释放资源,信号量加一,唤醒一个等待者。注意这里的关键是「信号量减到负数时,绝对值代表等待队列长度」,很多题目会拿这个做文章。

接下来是四步解题模板。第一步,数清楚题目里有几个资源、几个进程角色;第二步,为每个共享资源定义一个信号量,初值设为资源数量;第三步,在关键代码段的进入区放 P,退出区放 V;第四步,检查是否存在多个资源需要同时获取的情况,如果有,必须保证 P 的顺序一致,否则会死锁。以最经典的生产者-消费者为例,完整代码:

#define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int in = 0, out = 0; semaphore mutex = 1; // 互斥访问缓冲区 semaphore empty = BUFFER_SIZE; // 空槽位数量,初值为缓冲区大小 semaphore full = 0; // 满槽位数量,初值为 0 void producer() { while (1) { produce_item(); P(&empty); // 请求一个空槽位,没有空位就阻塞 P(&mutex); // 进入临界区,互斥访问缓冲区 buffer[in] = item; in = (in + 1) % BUFFER_SIZE; V(&mutex); // 离开临界区 V(&full); // 满槽位加一,可能唤醒消费者 } } void consumer() { while (1) { P(&full); // 请求一个满槽位,没有数据就阻塞 P(&mutex); // 进入临界区 item = buffer[out]; out = (out + 1) % BUFFER_SIZE; V(&mutex); // 离开临界区 V(&empty); // 空槽位加一,可能唤醒生产者 } }

这段代码里最需要注意的是 P 操作的顺序:必须先 P(empty) 再 P(mutex),不能反过来。如果先 P(mutex) 再 P(empty),当缓冲区满时,生产者会拿着 mutex 阻塞在 P(empty) 上,消费者无法进入临界区取数据,就死锁了。这个顺序问题几乎年年考,答题时把「先资源后互斥」写进结论里,是一个很稳的拿分点。

另一个高频变体是读者-写者问题。这类题目的核心是「写者优先还是读者优先」,不同策略信号量设计不一样。最简单的读者优先方案:一个 read_count 记录读者数量,一个 mutex 保护 read_count,一个 write_mutex 保证写者独占。注意 read_count 是普通整数不是信号量,它也需要 mutex 保护,这个细节经常被忽略。

3.2 银行家算法:手算安全序列的固定动作

银行家算法是死锁章节的必考计算题,难度不高但步骤繁琐,很多同学在考场上一紧张就把 Available 和 Need 算错。先明确四个矩阵的物理含义:Max 是进程最大需求,Allocation 是已分配资源,Need 是还需要多少资源(Need = Max - Allocation),Available 是系统剩余资源。做题的第一步永远是补全 Need 矩阵,而不是急着去找安全序列。

手算安全序列的固定动作分四步:第一,用 Available 逐个比对进程的 Need,找出所有 Need 每一项都小于等于 Available 的进程;第二,假设选其中一个进程执行完,归还它的 Allocation,更新 Available = Available + Allocation;第三,重复第一步,直到所有进程都能执行完,则存在安全序列;第四,如果某一步找不到满足条件的进程,说明系统处于不安全状态。这里有一个考场技巧:多个进程同时满足条件时,任意选一个都能推出安全序列,因为银行家算法只要存在一条安全路径即可。

做题时最容易错的不是算法本身,而是 Available 的初始值。题目通常会给「某时刻资源分配情况表」,你需要先算出此刻的 Available = 总资源 - 所有进程 Allocation 之和。这个减法一旦算错,后面全部白做。我的习惯是在草稿纸上先写一行「总资源 = (A, B, C)」,再写一行「已分配总和 = (...)」,两者相减得到 Available,然后再开始找安全序列。

3.3 页面置换与磁盘调度:用对比表记清判定标准

页面置换算法考得最多的是 OPT、FIFO、LRU 三种,题目一般给一个访问序列和三个物理块,让你分别写出缺页次数。这里最大的坑是:OPT 是从当前位置往后看未来的访问序列,FIFO 只看进入内存的时间,LRU 只看过去最近的使用情况。三种算法的「目光方向」不同,很多同学把 LRU 和 OPT 搞混,就是因为没意识到一个是看过去、一个是看未来。

做题时我习惯画一个三行表格,行是三个物理块,列是访问序列的每一步。每来一个页面,先看是否命中,再看是否需要置换。需要置换时,OPT 选未来最远才被访问的页面淘汰,LRU 选过去最久没被访问的页面淘汰,FIFO 选最早进入的页面淘汰。注意 FIFO 和 LRU 在序列较短时结果经常一样,容易被误判为等价,实际上 FIFO 可能存在 Belady 异常,LRU 不会,这是简答题的经典考点。

磁盘调度算法也类似,SSTF 选离当前磁头最近的请求,SCAN 先朝一个方向移动到最远再回头,C-SCAN 只朝一个方向服务然后直接跳回起点。考试如果给的是计算题,注意 SCAN 的「当前移动方向」是题目指定的,不要自己假设;如果方向写反,整个磁道移动距离全部算错。这两个算法建议用一张小表对比记忆:算法、选择标准、是否考虑方向、是否可能饥饿,四个维度列一下就清楚了。

4. Linux命令与系统调用实操:让抽象概念变成能观察的行为

4.1 用strace把系统调用从黑匣子变成日志

操作系统课程里最抽象的部分是「陷入内核」和「系统调用」,概念上背得再熟,不如亲眼看一次。Linux 下有一个命令叫 strace,可以跟踪一个程序执行过程中发起的每一次系统调用。比如对一个最简单的ls命令执行strace -c ls,它会统计这个命令调用了多少次 open、read、write、close,这些数字直接把「用户态到内核态的切换」变成了可见的日志。

我一般建议在复习阶段跑这样一组命令:先strace ls看文件相关的系统调用,再strace -e trace=process sleep 1看进程相关的 fork、exec、wait,最后strace -c看系统调用次数分布。跑完之后对照教材里的「系统调用是操作系统提供给应用程序的接口」这句话,你会发现理解深度完全不一样。注意 strace 输出里每一行都是一次系统调用,参数里的 fd 数字是文件描述符,0/1/2 分别对应标准输入、标准输出、标准错误,这个细节在分析输出时很有用。

4.2 fork与僵尸进程:用一段C代码验证进程生命周期

进程章节的考点「进程状态转换」和「僵尸进程」光靠背图很容易忘。一个可复现的做法是写一段 C 代码主动制造僵尸进程,然后用 ps 命令观察它。以下代码在子进程中先打印自身 PID 然后退出,父进程 sleep 30 秒不调用 wait,这段时间里子进程就是僵尸状态:

#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); // 调用一次,返回两次 if (pid < 0) { perror("fork failed"); return 1; } if (pid == 0) { // 子进程分支:打印自己的 PID 后立即退出 printf("child pid: %d\n", getpid()); _exit(0); // 注意用 _exit 而不是 exit,避免刷新父进程的缓冲区 } else { // 父进程分支:sleep 30 秒,期间不回收子进程 printf("parent pid: %d, child pid: %d\n", getpid(), pid); sleep(30); wait(NULL); // 30 秒后回收子进程,僵尸状态结束 } return 0; }

这段代码验证了两个考点:一是 fork 的返回值语义——父进程拿到子进程 PID,子进程拿到 0,这是判断代码走哪个分支的依据;二是僵尸进程的产生条件——子进程先退出、父进程未回收,子进程的 PCB 还留在内核里,ps 输出里状态栏显示为 Z。运行后在另一个终端执行ps -l,能看到状态为 Z 的进程;30 秒后 wait 执行,僵尸进程消失。这个实验做完,进程状态转换就不再是死记的图了。

4.3 用top和time观察调度与时间片

调度算法的考点之一是时间片轮转,教材里说「每个进程运行一个时间片后切换到下一个」。你可以在 Linux 里用一个简单的 shell 命令组合观察这个过程:time命令可以统计一个程序的真实时间、用户态 CPU 时间和内核态 CPU 时间,top命令可以实时看到进程的 CPU 使用率和状态。比如启动一个死循环程序while :; do :; done,再开top -d 1,你能看到这个进程的 CPU 占用接近 100% 且状态为 R(运行态),这对应教材里「就绪态进程被调度到 CPU 上运行」的描述。

想更直观地看时间片切换,可以同时启动多个这样的死循环,然后观察 top 里各进程的 CPU 时间是否交替增长。单核环境下,两个死循环进程的 CPU% 会交替在 50% 左右波动,这就是时间片轮转的宏观表现。注意现代 Linux 用的是 CFS 调度器,按虚拟运行时间而不是固定时间片调度,但「进程轮流占用 CPU」的观察结果依然成立。这个实验还能顺带验证一个考点:进程在用户态和内核态之间的切换是频繁发生的,time输出里的 real、user、sys 三个时间差就能说明问题。

5. 期末复习避坑指南:五个反复出现的扣分点

5.1 信号量初值随手写,导致整道 PV 题全错

现象:PV 操作题思路完全正确,P/V 位置也对了,但信号量初值写错,比如把空槽位信号量初值写成 0,把互斥信号量初值写成缓冲区大小,整道题直接不得分。

原因:初值不是「觉得差不多」就能定的,它的语义是「该资源当前可用数量」。互斥信号量初值为 1 表示资源同一时刻只能被一个进程占用;空槽位信号量初值为缓冲区大小;满槽位信号量初值为 0。初值一旦和语义脱节,后续所有 P/V 操作的意义都变了。

解决:拿到题目先圈出资源类型,逐个写清楚「这个信号量代表什么资源,初值为什么是这个数」。养成在代码开头用注释标注初值依据的习惯,哪怕考场上时间紧,这一步也不能省。

5.2 银行家算法 Available 算错,安全序列全盘皆输

现象:银行家算法计算过程步骤都对,但推出的安全序列和标准答案不一致,回头检查发现是最开始的 Available 就算错了。

原因:Available 不是题目直接给的,它等于系统资源总量减去所有进程已分配资源之和。很多同学图省事直接从题目表格里抄 Available,或者把某个进程的 Need 当成 Available,一步错步步错。

解决:动笔前先单独做一次减法,写成显式的一行:Available = 总资源 - ΣAllocation。把这一步当成算法的一部分,不要当成可以跳过的铺垫,能避开绝大多数计算错误。

5.3 页面置换 LRU 和 OPT 混淆,缺页次数算不对

现象:页面置换题里,OPT 和 LRU 的缺页次数总是算错一个,检查发现是把「看未来」和「看过去」搞反了。

原因:两种算法的淘汰标准方向相反。OPT 淘汰「未来最远才被访问」的页,LRU 淘汰「过去最久没被访问」的页。做题时如果只看「谁要被淘汰」而不标记参考方向,极容易在序列中间某一步开始走偏。

解决:每一步置换时,在淘汰页上标注理由:「未来最远 →」「过去最久 →」。写清楚依据不仅方便检查,也能在卷面上向阅卷老师展示你确实理解了算法语义,即使结果出错也能拿到部分过程分。

5.4 死锁的四个必要条件只背不应用

现象:简答题问「分析某段代码是否可能死锁」,只写出四个必要条件(互斥、持有并等待、不可剥夺、循环等待),然后不做任何结合代码的分析,被扣分。

原因:四个条件是判断工具,不是答案本身。题目要求的是「用条件分析具体场景」,而不是复述定义。只背工具不应用,等于没答到点上。

解决:答题时按固定结构写:先列出四个必要条件,然后逐个对照题目场景,说明哪个条件满足、哪个不满足。比如银行家算法的代码实现中,进程可以被剥夺资源,所以不满足「不可剥夺」条件,系统不会死锁——这种结合具体场景的结论才是得分点。

5.5 实验报告写得很厚,但复习时一眼不看

现象:课程实验做完、报告交完,复习阶段只翻教材和PPT,实验代码完全不看,结果考试遇到「结合实验说明系统调用过程」这类题只能空泛作答。

原因:实验是考点最好的实体化载体。比如用 C 语言写过生产者-消费者,PV 操作的语义就已经在实际代码里验证过了;用 strace 观察过系统调用,用户态与内核态的关系就不再是抽象概念。

解决:复习计划里给每个核心考点标注对应实验,考前把实验代码翻出来重跑一遍,重点看代码里和考点直接对应的那几行。不需要重新做完整个实验,但「代码里 PV 操作的具体位置」这种问题必须能在五分钟内指出来。

6. 最后一周冲刺:用全真模拟代替反复翻书

6.1 模拟考试的三条硬规则

考前最后一周,最容易犯的错是继续从头翻教材,觉得「再看一遍更安心」。实际上这一周最有效的动作是做三到五套真题模拟,而且要按考场规则执行。第一条硬规则:整套卷子计时做,中间不翻书、不查资料,手机放远一点。第二条硬规则:计算题和 PV 大题必须手写完整过程,不能在脑子里过一遍就算做完,手写能暴露步骤缺失和粗心错误。第三条硬规则:做完之后不是对答案就结束,而是把每道错题的知识点标回复习表里,如果某个考点连续两次错,就在考前最后一天集中看这一块的例题。

模拟时我习惯用「错题归因表」,每道错题记三列:错误类型(概念不清 / 计算粗心 / 步骤遗漏 / 读题偏差)、对应考点、纠正动作。这个表到考前最后两小时特别好用,因为这时候已经不适合再做大题,翻一遍归因表,看到的是「我容易在哪里翻车」,比重新看书高效得多。比如归因表里出现三次「PV 题忘记标注信号量初值语义」,考前最后一眼就看那个模板,而不是从第一章开始复习。

关于概念背诵题,我的做法是准备一页纸的背诵稿,把高频简答题浓缩成关键词串,每个题控制在三到五个关键词。比如「死锁的四个必要条件」就写「互斥 / 持有等待 / 不可剥夺 / 循环等待」,考场上靠关键词扩展成完整句子。这样能把背诵量压缩到最小,把精力留给更值钱的计算题。

最后说一个我自己的习惯:考前那天晚上不学新知识,只做两件事,一是把归因表从头看一遍,二是把四套真题的计算题全部复盘一遍。复盘是看思路不看答案,确保每道题第一步写什么、第二步写什么,脑子里有一条清晰的路径。这套方法我带过几届备考的同学,凡是认真执行的,即便平时概念题丢分不少,卷面总分也能被计算题托住。操作系统这门课,算得出来才叫真会,背得出来只是知道;希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询