操作系统期末复习指南:进程、调度、死锁与内存管理核心考点

发布时间:2026/10/24 15:25:43
操作系统期末复习指南:进程、调度、死锁与内存管理核心考点

简介:这份资料是面向山东大学操作系统课程期末复习的笔记型PDF,适合正在备考操作系统、需要系统梳理知识框架的本科生使用。内容围绕操作系统基本概念与功能展开,覆盖进程管理、存储管理、文件管理、设备管理、作业管理及文件系统管理等核心章节,并整理了进程状态转换、PCB组成、进程调度队列、父子进程与僵尸/孤儿进程、进程间通信的消息传递与共享内存对比等高频考点,还涉及操作系统启动流程、Simple/Layered/Microkernel三种结构设计及API与系统调用接口的关系。资源包共1个PDF文件,大小约2.91MB,便于打印或平板阅读。目前已有974人学习下载,说明该笔记在同类复习资料中具有一定参考价值,适合用于考前快速回顾与查漏补缺。

1. 操作系统期末:从进程状态图到银行家算法,一张卷子到底考什么

操作系统期末最反直觉的一点是:背得最熟的概念题往往只占一小部分,真正拉开分差的是进程状态转换、调度计算、信号量代码和死锁判断这几类“要么全对要么全错”的题。这份复习笔记覆盖 U1 到 U11,从导论、系统结构、进程、线程、CPU 调度、进程同步、死锁、内存管理、虚拟内存到文件系统接口与实现,基本把一学期的考点压进了一条主线:先建立“操作系统在管什么”的框架,再用进程和内存两条腿撑起所有计算与代码题。适合正在刷往年卷、想把零散笔记串成答题模板的人,也适合面试前需要快速回忆 PV 操作、页面置换和调度算法的人。

2. 进程与线程:状态图、PCB 和父子进程的代码题怎么答

2.1 进程状态转换图:四个箭头对应四种时机

进程是某一特定功能的程序的一次执行过程,是操作系统中最基本的单位。进程与程序的区别几乎是必考简答:进程由程序和数据组成,离开程序没有意义;程序是静态的,进程是动态的;进程有生命周期,短暂,程序相对长久;一个程序可以对应多个进程。

状态转换图要画出运行、等待、就绪三个状态,四个箭头分别是:

  • 运行到等待:等待某事件发生,比如发出 I/O 请求。
  • 等待到就绪:等待的事件发生了。
  • 运行到就绪:时间片到,或有更高优先级进程出现。
  • 就绪到运行:被调度程序选中。

答题时不要只画图,每个箭头后面补一句触发条件,阅卷时按点给分。PCB 是系统为了管理进程设置的专门数据结构,记录进程的外部特征,描述进程的运动变化过程。进程三要素是程序、数据、PCB。

2.2 父子进程代码题:pid 判断和僵尸、孤儿进程

代码题常考 fork 之后的输出判断。核心规则:子进程 pid 等于 0,父进程 pid 大于 0;写时复制让父子进程各自变量互不影响。

#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); // 创建子进程 if (pid < 0) { fprintf(stderr, "fork failed\n"); return 1; } else if (pid == 0) { // 子进程分支:pid 为 0 printf("child process\n"); } else { // 父进程分支:pid 为子进程标识符 wait(NULL); // 父进程等待子进程结束 printf("parent process\n"); } return 0; }

这段代码里 fork 之后两个进程从同一位置继续执行,但返回值不同。子进程走 pid==0 分支,父进程走 else 分支。wait 的作用是让父进程阻塞,直到某个子进程终止,并返回终止子进程的进程标识符。如果子进程终止而父进程没调用 wait,子进程变成僵尸进程;如果父进程没调用 wait 就终止,子进程变成孤儿进程,在 Linux 和 Unix 中由 init 接管。

进程终止还有级联终止:父进程终止后子进程自动终止。这些术语在选择题和简答题里反复出现,建议把“谁先死、谁没 wait、结果叫什么”做成一张小表背下来。

2.3 线程:用户线程与内核线程的取舍

线程是 CPU 使用的基本单元。引入线程的理由有四条:响应度高,部分线程阻塞其他线程仍可执行;资源共享,同一进程的线程共享内存和资源;经济,创建和切换代价比进程小;多处理器体系结构利用,一个进程的多个内核线程可运行在不同处理器上。

用户线程由用户空间库管理,不支持抢占式调度;内核线程由操作系统直接支持和管理,线程阻塞不相互影响,切换代价接近进程。多线程模型有多对一、一对一、多对多三种。线程取消分异步撤销和延迟撤销,线程池预先创建线程等待工作。这部分常出选择题,判断“谁管理、谁切换代价大、阻塞是否影响其他线程”。

3. CPU 调度与死锁:计算题和银行家算法的固定套路

3.1 调度算法对比:FCFS、SJF、RR 和优先级

CPU 调度是计算题重灾区。先把几个算法特征记牢:

算法抢占性关键特征典型问题
FCFS非抢占先到先服务护航效果,短进程被长进程拖慢
SJF非抢占最短作业优先,最小等待时间长进程可能饥饿
SRTF抢占最短剩余时间优先需持续比较剩余时间
HRRN非抢占最高响应比优先兼顾等待时间
优先级两者均可高优先级先执行低优先级饥饿,用老化解决
RR抢占时间片轮转q 太大退化成 FCFS,q 太小切换开销大

分派程序负责切换上下文、切换到用户模式、跳转到用户程序合适位置,它停止一个进程启动另一个所花的时间叫分派延迟。衡量指标包括 CPU 使用率、吞吐量、周转时间、等待时间、响应时间。需要最大化 CPU 使用率和吞吐量,最小化周转、等待和响应时间,通常看平均值。交互系统里,最小化响应时间的方差比最小化平均响应时间更重要。

多级队列调度把就绪队列分成多个独立队列,按进程属性分配,队列间一般固定优先级抢占。多级反馈队列允许进程在队列间移动,占 CPU 过多的进程降到低优先级队列,等待过长的进程升到高优先级队列,I/O 约束和交互进程留在高优先级队列。两者设计思想的不同点常考 10 分简答:多级队列是静态分配、队列间固定优先级;多级反馈队列是动态调整、允许移动,更复杂也更常用。

3.2 死锁四个必要条件与银行家算法

死锁是一组进程各自持有资源又申请其他进程持有的资源,进入循环等待。四个必要条件:互斥、占有并等待、非抢占、循环等待。资源分配图中没有环一定无死锁;有环且每个资源只有一个实例则死锁;有环但资源有多个实例可能死锁。

死锁处理有三条路:预防、避免、检测与恢复。预防是静态策略,破坏至少一个必要条件;避免是动态策略,用安全状态判断。安全状态指存在进程序列,每个进程仍可申请的资源数小于当前可用资源加上前面进程占用的资源。安全状态不会死锁,不安全状态可能死锁。

银行家算法是必考计算。每个进程进入系统时说明每种资源最大需求,申请时系统计算分配后是否仍安全,安全才分配。答题步骤固定:先算 Need 矩阵,再找 Available 能满足的进程,假设它完成并释放资源,重复直到所有进程排入序列。排不进去就说明不安全。

示例:三类资源 A/B/C,Available = (3,3,2) 进程 Allocation Max Need P0 (0,1,0) (7,5,3) (7,4,3) P1 (2,0,0) (3,2,2) (1,2,2) P2 (3,0,2) (9,0,2) (6,0,0) P3 (2,1,1) (2,2,2) (0,1,1) P4 (0,0,2) (4,3,3) (4,3,1)

先找 Need 小于等于 Available 的进程,P1 和 P3 满足。假设 P1 完成,Available 变为 (5,3,2),再找下一个。按这个顺序写出安全序列,每一步都要写清 Available 的变化,否则过程分拿不全。

3.3 饥饿与死锁的异同

简答题常问饥饿和死锁的异同。相同点:都由竞争资源引起。不同点:死锁进程都处于等待状态,饥饿可能出现在忙等待进程;死锁等待永远不会释放的资源,饥饿等待会被释放但不会分配给自己的资源;死锁一定循环等待,饥饿不一定;死锁涉及多个进程,饥饿可能只有一个;饥饿时系统至少有一个进程能正常运行,死锁可能使整个系统崩溃。

4. 进程同步:信号量代码题和 PV 操作的答题模板

4.1 临界区三条件与 Peterson 算法

临界区是每个进程中可能改变共同变量、更新表、写文件的代码段,没有两个进程可以同时在临界区内执行。解决方案要满足三个条件:互斥、有空让进、有限等待。Peterson 算法是软件方法,用于两个进程在临界区和剩余区交替执行。硬件同步用 TestAndSet 原子指令,检查和修改字的内容或交换两个字的内容,自动执行不可中断。

4.2 生产者消费者与读者写者:信号量代码

信号量 S 是整数变量,除初始化外只能通过 P 和 V 操作访问。计数信号量值域不受限,二进制信号量只能为 0 或 1,也叫互斥锁。自旋锁是连续循环忙等待的信号量,单处理器系统中忙等待浪费 CPU,多处理器系统中一个线程自旋时另一线程可在另一处理器执行。

生产者消费者问题:一群生产者生产产品放入 n 个缓冲区的缓冲池,消费者从缓冲区取走产品。用三个信号量:mutex 互斥访问缓冲区,empty 表示空缓冲区数量,full 表示满缓冲区数量。

semaphore mutex = 1; // 互斥访问缓冲池 semaphore empty = n; // 空缓冲区数量 semaphore full = 0; // 满缓冲区数量 // 生产者 while (true) { produce_item(); P(empty); // 等待空缓冲区 P(mutex); // 进入临界区 insert_item(); V(mutex); // 离开临界区 V(full); // 满缓冲区加一 } // 消费者 while (true) { P(full); // 等待满缓冲区 P(mutex); // 进入临界区 remove_item(); V(mutex); // 离开临界区 V(empty); // 空缓冲区加一 consume_item(); }

P 操作顺序不能颠倒:如果先 P(mutex) 再 P(empty),生产者可能在持有互斥锁时阻塞,消费者无法进入临界区取走产品,形成死锁。V 操作顺序不影响正确性,但习惯上先释放互斥再增加计数。

读者写者问题:写者要对数据库排他访问,读者可同时读。读者优先方案里,第一个读者进入时 P 写锁,最后一个读者离开时 V 写锁,用 read_count 计数。

semaphore rw_mutex = 1; // 读写互斥 semaphore mutex = 1; // 保护 read_count int read_count = 0; // 读者 P(mutex); read_count++; if (read_count == 1) P(rw_mutex); // 第一个读者锁住写者 V(mutex); read_database(); P(mutex); read_count--; if (read_count == 0) V(rw_mutex); // 最后一个读者释放写者 V(mutex); // 写者 P(rw_mutex); write_database(); V(rw_mutex);

信号量和互斥锁的区别也常考:信号量用于同步,互斥锁用于互斥;互斥锁只能 0 或 1,信号量可为其他整数;互斥锁加锁解锁由同一线程使用,信号量可以一个进程释放另一个线程得到。

5. 内存与虚拟内存:分页、分段和页面置换的计算题

5.1 连续分配与非连续分配:内碎片和外碎片

内存管理机制分连续空间分配和非连续分配。固定分区把用户空间划成固定大小分区,每个分区装一个进程,产生内碎片。可变分区根据进程大小动态建立分区,连续可用内存空间叫孔,分配策略有首次适应、最佳适应、最差适应。外碎片是可用内存总和满足请求但不连续,用紧缩解决。

分页把用户进程空间分成相同大小的页,物理内存分成对应的帧。页表基寄存器 PTBR 存页表起始物理地址,页表长度寄存器 PTLR 存页表大小。TLB 是快表,只存页表一部分,查找时并行比较。二级页表要访问三次内存:两次页表加一次主存。有效位表示页在逻辑地址范围内,无效位表示不在。共享页里共享代码必须可重入,即不能自我修改。

分段按程序自身逻辑划分,每段有段号,内存动态划分为长度不同的物理段,每段占连续空间但段间可不相邻。地址映射过程:CPU 取逻辑地址,用段号查段表得到该段内存起始地址,加上段内偏移得物理地址。分段分页比较常考:分页对用户透明、大小固定、有内碎片;分段对用户可见、大小可变、有外碎片。

5.2 页面置换算法:FIFO、LRU 和时钟算法

虚拟内存把用户逻辑内存和物理内存分开,好处包括弥补物理内存不足、提高反映速度、减少物理内存读取、允许共享页。按需调页只在执行需要时载入页,访问未调入内存的页产生缺页陷阱。缺页率等于缺页次数除以访问页面总数。

页面置换算法要会手算缺页次数:

  • FIFO:替换最先调入的页,可能出现 Belady 异常。
  • 最优置换:替换未来最远才访问的页,只能用于比较。
  • LRU:替换最近最少使用的页,计数器实现复制时钟值,栈实现把引用页移到栈顶。
  • 二次机会:引用位为 0 就置换,为 1 就挪到链表尾并清零。
  • 时钟算法:指针循环扫描,是二次机会的实现形式。
  • 增强二次机会:优先置换最近没使用没修改的页,使用位权重高于修改位。
  • LFU 置换计数最小的页,MFU 置换计数最大的页。

帧分配有平均分配和比例分配,全局置换从所有帧中选,局部置换只从自己分配的帧中选。系统颠簸是频繁调页,若换页时间大于运行时间就是颠簸,用页错误率策略调整帧数。

5.3 文件系统实现:FCB 查找和三种分配方式

文件系统如何依据文件名找到 FCB 是高频简答。系统先调用 open(),把文件名传给文件系统,搜索目录结构找到文件后,FCB 复制到系统范围内打开文件表,单个进程打开文件表增加一个条目,通过指针指向系统表条目,open() 返回指向该条目的指针。

文件空间分配三种方式:连续分配访问性能最好但有外部碎片;链接分配无外部碎片但指针损坏影响可靠性,不能有效支持直接访问;FAT 把散落指针收拢,下标是块号,值指向下一个块号,便于快速访问和高速缓存。FAT32 每项占 32 位即 4 字节。

6. 易错点:这五类题每年都有人丢分

6.1 进程与程序的区别答成“动态和静态”就完了

错在哪:只写“程序静态、进程动态”,漏掉进程由程序和数据组成、一个程序可对应多个进程、进程有生命周期。为什么错:把简答当名词解释,采分点没踩全。怎么答对:按“组成、动静、生命周期、对应关系”四条展开,每条一句话,稳拿满分。

6.2 银行家算法只写安全序列不写 Available 变化

错在哪:直接给出 P1、P3、P0 的顺序,中间没有资源回收过程。为什么错:阅卷按步骤给分,跳步等于放弃过程分。怎么答对:每一步写“假设 Pi 完成,Available = 原 Available + Allocation_i”,再找下一个 Need 满足的进程,直到序列排完。

6.3 生产者消费者里 P 操作顺序写反

错在哪:先 P(mutex) 再 P(empty)。为什么错:生产者持有互斥锁时可能因缓冲区满而阻塞,消费者进不了临界区,死锁。怎么答对:资源信号量 P 在前,互斥信号量 P 在后;V 操作顺序相反,先 V(mutex) 再 V(full) 或 V(empty)。

6.4 页面置换把 FIFO 和 LRU 的替换对象搞混

错在哪:FIFO 替换最近最少使用的页。为什么错:FIFO 看调入时间,LRU 看最近访问时间,两者依据不同。怎么答对:FIFO 找最早进入内存的页,LRU 找最久没被访问的页,做题时在页表旁标调入顺序或访问顺序,别凭感觉。

6.5 死锁和饥饿的异同只写“都是资源竞争”

错在哪:相同点只写一句,不同点漏掉循环等待和进程数量。为什么错:这是 10 分简答,采分点分散。怎么答对:相同点写资源竞争;不同点按等待状态、资源是否释放、是否循环等待、涉及进程数、系统是否崩溃五条对比,每条一行。

7. 押题思路:把 U5 到 U9 的计算模板练成肌肉记忆

如果只剩三天,优先顺序是:进程同步代码题、银行家算法、页面置换缺页计算、调度算法等待时间计算、进程状态转换简答。这五类题占分高且题型固定,练熟一套模板就能覆盖大部分变体。

具体做法:拿一张 A4 纸,左边写算法名,右边写三步模板。调度算法模板是“画甘特图、算等待时间、算周转时间”;银行家算法模板是“算 Need、找可满足进程、回收资源写 Available”;页面置换模板是“列表格、标访问序列、逐次判断是否缺页”;信号量模板是“定信号量含义、写 P 顺序、写 V 顺序、说明互斥与同步关系”。每做一道题就对照模板检查有没有跳步。

我自己的血泪经验是:银行家算法第一次做的时候觉得看懂了,考场上 Need 矩阵算错一行,后面全崩。从那以后我每次做这类题都强制走一遍“先列 Allocation、Max、Need 三列,再单独写 Available 行,每步回收后重新抄一遍 Available”的流程,哪怕觉得多余也不省。这个习惯让我在计算题上再没翻过车。

简答部分押题集中在:进程与程序区别、线程引入原因、死锁四个必要条件、死锁与饥饿异同、分段与分页比较、虚拟内存好处、FCB 查找过程。这些题答案都在笔记里有现成段落,背的时候按“定义加对比加场景”三层记,不要只背关键词。

代码题押 fork 输出判断和信号量伪代码。fork 题记住 pid 等于 0 是子进程、大于 0 是父进程、wait 回收僵尸;信号量题记住资源信号量在前、互斥信号量在后。把这两类各手写三遍,考场上直接默写。

最后一周每天抽 40 分钟做一套计算,20 分钟背简答,10 分钟默写代码模板。操作系统期末不是比谁背得多,是比谁在计算题上不跳步、在代码题上不写反顺序。希望帮到你。

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