
简介面向学习操作系统课程、正在对照《操作系统精髓与设计原理》第八版完成课后习题与复习的本科生、考研读者这份答案资料围绕进程管理、进程状态转换、进程调度、资源管理和并发编程等核心知识点展开可用于核对解题思路、梳理章节脉络并定位薄弱环节。压缩包内共1个docx文档大小约904KB内容按习题编号组织涵盖就绪态、运行态、阻塞态与非常驻态之间转换事件的说明进程调度中间策略的权衡分析以及依据时刻事件推演进程状态、判断阻塞等待事件、分析共享变量并发执行时输出顺序与取值范围的解答过程。该资料已有7520人学习适合在独立完成习题后对照参考也便于考前复盘状态转换图、调度算法和并发程序分析等高频考点。1. 进程状态图为什么值得搞懂一台电脑里“排队”的真相打开任务管理器几十个进程同时在跑而真正在处理器上执行的同一时刻只有那么一两个。操作系统习题答案里反复出现的那张进程状态图说到底就是把“谁在窗口前办事、谁在椅子上等、谁已经被请到门外”画成一张图。它回答一个很朴素的问题某个进程此刻到底在干什么下一秒又会因为什么被换下去。学进程管理时最容易卡住人的往往不是名词而是箭头的方向——运行什么时候退回就绪什么时候滑进阻塞为什么有的进程会被整段搬出内存。这些箭头正是这份“操作系统第八版习题答案”里被问得最多的部分也是后续调度、互斥、死锁所有题目的地基。2. 五个状态与六次转换进程从被创建到被挂起经历了什么进程管理这一章之所以难是因为教材习惯用一张图概括所有情况而初学者的第一反应是“这些方块看起来都一样”。其实每个状态只回答一件事这个进程现在缺什么。缺处理器是一种情况缺一个输入输出结果是另一种缺内存位置又是第三种。把“缺什么”想清楚六条箭头自然就顺了。2.1 就绪、运行、阻塞三个身份三种等待通俗地说就绪态是“菜洗好切好了只等灶台空出来”运行态是“正在灶上炒”阻塞态是“炒到一半发现盐没了出门买盐去”。关键区别在于就绪态缺的只有处理器一旦调度器点名立刻就能跑阻塞态缺的是别的东西——磁盘读完、键盘输入、某个信号量被释放——这时候就算把整台机器的处理器都空着给它它也跑不动。由此可以推出四条最基本的转换状态转换引发事件通俗解释就绪 → 运行被分派器选中分到处理器排到了上台运行 → 就绪进程被抢占时间片用完、更高优先级到达还没干完被叫下来重新排队运行 → 阻塞运行中发生必须等待的事件如发起磁盘读主动让出灶台去买盐阻塞 → 就绪等待的事件发生了如磁盘读完成产生中断盐买回来了重新排队等灶台这四条里最容易被写反的是第二条和第三条。区分方法很简单看进程是“被迫下台”还是“主动下台”。时间片到了被换走是运行转就绪它的活儿还没干完只是暂时没资格占着处理器发起一次磁盘读然后等结果是运行转阻塞它自己知道自己跑不下去了。很多课后答案只写“进程被抢占”五个字但真正的考点在于抢占之后它回到的是就绪队列不是阻塞队列。这里还有一个隐藏角色——分派器。调度策略决定“下一个该谁”分派器负责“把处理器真正交出去”。教材题目里说“由于该进程被分派器分派到处理器”强调的就是这一步是动作不是策略。策略和动作分开看进程调度那几道题就不会混。2.2 挂起态被搬出内存的进程去了哪儿第四个状态在教材里叫“非常驻态”更多地方写成“挂起态”细分还有就绪/挂起和阻塞/挂起两种。它和阻塞态最大的不同是位置阻塞态虽然没在跑但它的代码和数据还老老实实待在内存里挂起态则是整个进程被搬到磁盘上内存里可能一点痕迹都不留。为什么要这么干教材给的答案很实在内存里保存的进程已经达到上限又有新进程要创建或者系统并发度需要降低。打个比方餐馆里等位的客人太多椅子不够了只好请一部分人到门外先站着——人还是那些人但占的地方不一样了。于是多出两条转换就绪 → 就绪/挂起内存紧张或并发度要降把已经准备好但暂时轮不上的进程挪出去。阻塞 → 阻塞/挂起同样是内存里进程太多把正在等的进程连同它的等待状态一起挪到磁盘上。注意这两条的原因被教材归为同一类答题时不必硬编两个理由。真正需要分清的是一个进程被挂起不代表它等的事件消失了。阻塞/挂起的进程等的还是那个磁盘读完成或者信号量只是它现在不在内存里等事件来了还得先被调回来才能继续。反过来从挂起回到内存的那一侧通常叫激活。这一步教材没有在状态图里细画但理解上就是逆过程内存腾出位置了或者它等的事件已经发生、需要尽快处理就把它调回来。答题时如果题目只问“引发每个状态转换的事件”把正向六条写清楚就够了如果题目追问“那它怎么回来”答“内存有空间或事件已就绪时被激活调入”即可。这一层想明白后面那些带时刻表的长题才不会乱。2.3 把事件时间轴翻译成状态一道题背后的还原方法教材里那种“时刻 5、15、18、20……分别写出每个进程在时刻 22、37、47 的状态”的题看着吓人其实是体力活。它的解题套路只有三步跟查快递物流差不多。第一步画一张表。横轴是进程编号纵轴是时刻从最早的事件开始往下排。每个格子先留空等有事件落进去再填。第二步把事件翻译成状态变化。这一步靠的是 2.1 和 2.2 那张转换表但要补两个教材题里常埋的细节请求输入输出是运行转阻塞输入输出完成产生中断是阻塞转就绪。注意是“完成”才算发出请求那一刻只是开始等。换出是转入挂起调入是从挂起回来。中间隔着的那段时间该进程既不占内存也不参与调度。第三步处理“排队”这个坑。同一道题里磁盘单元 3 先后被三个进程碰过一个进程先读它另一个进程后来要写它还有一个进程稍后又要读它。这种共享设备必须串行使用后来者得等前面的用完。初学者最容易在这里出错——看到“时刻 24 某进程读磁盘单元 3”就直接判它阻塞却忘了它可能还在排队等前一个持有者。判阻塞没问题但要写清“等的是磁盘单元 3 空出来”而不是笼统写“等输入输出”。举个能确定的小例子某进程在时刻 20 发起读磁盘单元 2时刻 33 产生读完成中断那么它在 20 到 33 之间始终是阻塞态等的就是这次读完成33 之后转成就绪态重新排队等处理器。同理一个进程时间片结束是运行转就绪不是转阻塞因为它没在等任何外部事件。时刻表题的答案往往是一长串字母看着像密码。真正值钱的不是那串字母而是你能不能对着任意一个时刻说出“它为什么在这个状态、它在等谁”。这份习题答案里给出的状态序列配上你自己画的时间轴才算真正对上只抄序列下次换个时刻又不会了。3. 并发为什么会算出“错”答案读改写从来不是一步单看tally tally 1这一行任何人都会说结果加一。可一旦两个进程同时执行它结果就开始不受控制。原因不在代码写得对不对而在于这行代码在机器层面根本不是“一步”。3.1 两个进程各加 50 次结果为什么不是 100教材里那道经典题两个进程共享一个整型变量各自循环 50 次做自增最后打印这个变量。按直觉答案应该是 100实际可能小得离谱。因为一行自增编译后通常是三条指令把共享变量读进寄存器、寄存器加一、把寄存器写回共享变量。# 用生成器模拟两个进程的指令级交错 # mem 代表共享内存reg 代表每个进程私有的寄存器 def total(name, mem): for _ in range(50): reg mem[tally] # LOAD把共享变量读进自己的寄存器 yield # 此处可能被切换到另一个进程 reg 1 # ADD只改自己寄存器里的副本 yield mem[tally] reg # STORE把副本写回共享变量 yield这段代码不是真实实现只是把“三条指令”和“随时可能被切换”这两件事摆到明面上。关键参数只有两个mem[tally]是大家共用的那一个格子reg是每个进程各自的小本子。读的时候抄一份到自己本子上改的是本子上的数字只有写回那一刻才影响大家。问题就出在这儿从抄到写回之间别人可能已经把新数字写进去了你一写回就把人家的成果盖掉了。这正是并发题目里最反直觉的地方两个进程都没有算错各自都老老实实做了 50 次加一可最后的结果却对不上。翻车不是因为谁写错了代码而是因为“读—改—写”这三步之间存在一个可以被插队的窗口。3.2 上界 100、下界 2 是怎么卡出来的上界好想两个进程完全错开执行一个做完 50 次另一个再做 50 次中间没有任何交错结果就是 100。这也是最理想的情况说明并发本身不必然出错只是不保证。下界需要一步步推。设两个进程为 A 和 B共享变量初始为 0A 执行读指令把 0 抄进自己的寄存器此时被切走。B 完整跑完 49 次自增共享变量变成 49。A 恢复执行加一自己寄存器里是 1然后写回共享变量被改成 1——49 被盖掉了。B 进入下一轮读到的共享变量已经是 1抄进自己的寄存器。A 一口气把剩下的自增全部做完共享变量涨到 50。B 执行加一寄存器里是 2写回最终结果停在 2。所以最终结果落在 2 到 100 之间。教材进一步把它推广如果有 N 个这样的进程每个都做 50 次范围就本文还有配套的精品资源点击获取