ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

汤小丹操作系统课后题避坑指南:银行家算法、PV操作与页面置换手算技巧

汤小丹操作系统课后题避坑指南:银行家算法、PV操作与页面置换手算技巧 简介这份资料是汤小丹《计算机操作系统》教材的课后习题参考答案面向高校计算机专业学生、考研复习者以及准备操作系统相关面试的开发者用于课后巩固、期末复习与知识点自查。压缩包内共1个doc文档约654KB按章节整理可直接检索查阅。内容覆盖操作系统的主要目标与作用、计算机资源抽象、多道批处理与分时系统的形成动力、实时系统及硬实时与软实时任务的区分并系统梳理了OS的并发性、共享性、虚拟性和异步性四大特征以及处理机管理、内存管理、设备管理和文件管理的主要功能与任务。每道题均给出条理清晰的解答如脱机I/O与联机I/O的区别、分时系统与实时系统在交互性、及时性、可靠性上的比较、微内核OS的客户/服务器模式与优点等便于读者对照教材逐章核对答案、理解概念脉络。目前已有3900人学习下载适合需要系统刷题与查漏补缺的操作系统学习者。1. 汤小丹版操作系统课后题为什么“对答案”反而容易挂科很多人拿到《计算机操作系统》汤小丹版的课后习题第一反应是找一份“课后答案”对着抄。我当年也这么干过结果期末卷子上那道“银行家算法求安全序列”的题我明明背过答案却因为题目把 Available 和 Need 矩阵换了个顺序直接算崩。后来才想明白这门课的课后题不是用来“对答案”的而是用来暴露你对进程同步、内存分配、页面置换这些机制的理解漏洞的。汤小丹这本教材的习题有个特点——计算量大、状态转移多、边界条件刁钻光看答案根本不知道中间那步为什么这么跳。所以这篇笔记不打算给你一份“标准答案合集”而是把课后题里最高频的几类题型拆成可复现的解题路径银行家算法怎么手算不出错、PV 操作怎么从语义反推代码、页面置换缺页率怎么列表格不丢分。适合正在学这门课、准备考研复试、或者带学生做实验的从业者。你照着下面的步骤走一遍比背十份答案都管用。2. 银行家算法课后题从“背答案”到“手推安全序列”2.1 为什么汤小丹的银行家算法题总让人翻车汤小丹教材里银行家算法的课后题通常给一张表Process、Allocation、Max、Available然后让你求 Need 矩阵、找安全序列、判断某次请求能否分配。很多人翻车不是因为不会算而是因为算到一半忘了更新 Available。我见过最典型的血泪经验一个同学把 P1 释放后的资源加回 Available接着算 P2 时却用了旧的 Available整条安全序列全错。银行家算法的本质是一个状态搜索问题——每选一个进程系统状态就变一次你必须像调试器一样跟踪每一步的 Work 和 Finish。教材课后题之所以反复考就是因为它能逼你养成“每步更新、每步记录”的习惯。下面我给出一个通用的手算模板你拿任何一道汤小丹的课后题套进去都不会乱。2.2 手算安全序列的固定五步法附 Python 验证脚本先看一道典型题5 个进程 P0~P43 类资源 A/B/C。题目给出 Allocation 和 MaxAvailable 初始为 (3,3,2)。要求判断是否存在安全序列。我一般会按下面五步走每一步都在草稿纸上写清楚。第一步算 Need 矩阵。Need Max - Allocation逐行相减负数说明题目数据有误。第二步初始化 Work AvailableFinish 全为 false。第三步找满足 Need[i] ≤ Work 的进程。注意是每个分量都 ≤不是总和。第四步假设该进程完成Work Work Allocation[i]Finish[i] true。第五步重复第三步直到所有 Finish 为 true安全或找不到可执行进程不安全。下面这段 Python 脚本可以直接验证你的手算结果把题目数据填进去就能跑# 银行家算法安全序列验证脚本 # 适用汤小丹《计算机操作系统》课后习题典型数据 def is_safe(available, max_mat, alloc): n len(max_mat) # 进程数 m len(available) # 资源类数 need [[max_mat[i][j] - alloc[i][j] for j in range(m)] for i in range(n)] work available[:] finish [False] * n safe_seq [] while len(safe_seq) n: found False for i in range(n): if not finish[i] and all(need[i][j] work[j] for j in range(m)): # 模拟进程 i 执行完成释放其已占资源 for j in range(m): work[j] alloc[i][j] finish[i] True safe_seq.append(fP{i}) found True break if not found: return False, [] # 存在死锁无安全序列 return True, safe_seq # 以教材常见数据为例 available [3, 3, 2] max_mat [[7,5,3],[3,2,2],[9,0,2],[2,2,2],[4,3,3]] alloc [[0,1,0],[2,0,0],[3,0,2],[2,1,1],[0,0,2]] ok, seq is_safe(available, max_mat, alloc) print(安全: , ok, 序列:, seq)逻辑说明脚本严格按五步法实现need矩阵自动计算work每轮更新finish标记已完成进程。参数说明available是初始可用资源向量max_mat是最大需求矩阵alloc是已分配矩阵。运行结果会输出安全序列比如P1 - P3 - P4 - P0 - P2。如果你手算的序列和它不一样但都安全也是对的——安全序列不唯一这是汤小丹课后题常设的陷阱别因为对不上“参考答案”就怀疑自己。2.3 请求分配判断题多问一句“然后呢”课后题第二类考法是某进程发出 Request 向量问能否分配。很多人只检查Request ≤ Need和Request ≤ Available就下结论漏了最关键的一步——试分配后系统是否仍安全。正确做法是先假装分配修改 Available、Allocation、Need然后重新跑一遍安全序列检测。如果安全才真正分配否则回滚。我习惯在草稿纸边上画一个“试分配区”和原状态分开写避免改乱。这个习惯在考场上救过我至少两次。3. PV 操作课后题从语义反推代码而不是背代码3.1 汤小丹 PV 题的出题套路汤小丹教材的 PV 操作课后题几乎都围绕生产者-消费者、读者-写者、哲学家进餐三个模型变体。题目通常给一段自然语言描述让你用 P、V 原语写出同步算法。很多人背了标准答案但题目一改条件就懵——比如把缓冲区从 1 个改成 n 个或者把“读者优先”改成“写者优先”。根本原因是你背的是代码不是信号量的语义。PV 操作的核心就一句话P 表示申请资源V 表示释放资源信号量的值代表当前可用资源数。你只要把题目里的“等待条件”翻译成 P“完成后的通知”翻译成 V代码自然就出来了。3.2 用“资源视角”重写生产者-消费者以最常见的单缓冲区生产者-消费者为例。题目描述生产者往缓冲区放数据消费者取数据缓冲区满时生产者等空时消费者等。用资源视角拆解缓冲区空位 一种资源初始有 1 个生产者需要 P 它消费者取走后 V 它。缓冲区已有数据 另一种资源初始 0 个消费者需要 P 它生产者放入后 V 它。互斥访问缓冲区 一个互斥信号量 mutex初始 1。对应代码// 单缓冲区生产者-消费者汤小丹教材典型模型 semaphore empty 1; // 空位数 semaphore full 0; // 数据数 semaphore mutex 1; // 缓冲区互斥锁 // 生产者 void producer() { while (1) { produce_item(); P(empty); // 申请一个空位满则阻塞 P(mutex); // 进入临界区 put_item(); V(mutex); // 离开临界区 V(full); // 通知消费者多了一个数据 } } // 消费者 void consumer() { while (1) { P(full); // 申请一个数据空则阻塞 P(mutex); get_item(); V(mutex); V(empty); // 通知生产者多了一个空位 consume_item(); } }逻辑说明P(empty)必须在P(mutex)之前否则可能死锁——这是汤小丹课后题最爱考的“顺序陷阱”。参数说明empty初值为缓冲区容量full初值为 0mutex初值为 1。如果题目改成 n 个缓冲区只需把empty初值改成 n其余不变。你看根本不用背新代码。3.3 读者-写者加一个计数器就变“写者优先”读者-写者问题是汤小丹课后题的高频变体。标准“读者优先”版本里读者只要有一个在读写者就得等。实现关键是第一个读者负责 P 写锁最后一个读者负责 V 写锁中间用一个count计数器。代码骨架semaphore rmutex 1; // 保护 count semaphore wmutex 1; // 写锁 int count 0; void reader() { P(rmutex); if (count 0) P(wmutex); // 第一个读者锁住写者 count; V(rmutex); read(); P(rmutex); count--; if (count 0) V(wmutex); // 最后一个读者释放写者 V(rmutex); } void writer() { P(wmutex); write(); V(wmutex); }如果题目要求“写者优先”常见做法是再加一个信号量w读者和写者都先 P(w)写者优先获得。这个变体在汤小丹课后题里出现过多次你只要抓住“谁先 P 谁优先”的原则就能推出来。4. 页面置换课后题缺页率表格怎么列才不丢分4.1 OPT、FIFO、LRU 的手算差异汤小丹教材内存管理章节的课后题几乎必考页面置换算法给一个页面引用串比如7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1物理块数为 3让你分别用 OPT、FIFO、LRU 求缺页次数和缺页率。很多人算 FIFO 时忘了“Belady 异常”算 LRU 时把最近最久未使用和最近未使用搞混。我一般会画一张表每一列是一个引用页每一行是一个物理块表头标注“是否缺页”。OPT 看未来FIFO 看进入时间LRU 看最近访问时间。下面用 Python 模拟三种算法你可以拿它验证手算结果# 页面置换算法模拟OPT / FIFO / LRU def page_faults(ref_str, frames, algo): mem [] faults 0 for i, page in enumerate(ref_str): if page in mem: if algo LRU: mem.remove(page) mem.append(page) # 最近使用移到末尾 continue faults 1 if len(mem) frames: mem.append(page) else: if algo OPT: # 找未来最长时间不再使用的页 farthest, idx -1, -1 for j, m in enumerate(mem): try: nxt ref_str[i1:].index(m) except ValueError: nxt float(inf) if nxt farthest: farthest, idx nxt, j mem[idx] page elif algo FIFO: mem.pop(0) mem.append(page) elif algo LRU: mem.pop(0) # 最久未使用在头部 mem.append(page) return faults ref [7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1] for a in [OPT,FIFO,LRU]: f page_faults(ref, 3, a) print(f{a}: 缺页 {f} 次, 缺页率 {f/len(ref):.2%})逻辑说明mem列表模拟物理块FIFO 用pop(0)淘汰最早进入的LRU 用pop(0)淘汰最久未使用的因为每次访问命中都会把页移到末尾。参数说明ref_str是页面引用串frames是物理块数algo取OPT/FIFO/LRU。运行后你会看到 OPT 缺页最少FIFO 可能出现 Belady 异常增加物理块反而缺页更多LRU 介于两者之间。手算时建议用铅笔因为 OPT 需要反复看未来串容易看花眼。4.2 缺页率计算的两个边界坑第一个坑引用串第一个页一定缺页但很多人算缺页率时把总访问次数算错比如把重复引用漏算。第二个坑物理块数初始为空前 frames 次访问即使页面不同也一定缺页别以为“内存里没有但之前出现过”就不算缺页。汤小丹课后题经常在引用串里埋重复页就是考你这两点。我习惯在表格最下面单独写一行“累计缺页数”每列更新一次最后除以总列数这样不会乱。5. 避坑与排查课后题里最容易翻车的 4 个点5.1 现象银行家算法安全序列和参考答案不一样原因安全序列不唯一只要每一步都满足 Need ≤ Work就是合法序列。解决用第 2 章的 Python 脚本验证你的序列只要脚本判定安全就说明你的答案正确不要强行改成参考答案的顺序。5.2 现象PV 操作代码运行结果死锁原因P 操作顺序反了。比如生产者先 P(mutex) 再 P(empty)当缓冲区满时生产者持有 mutex 等待 empty消费者无法进入临界区释放 empty死锁。解决永远先 P 资源信号量empty/full再 P 互斥信号量mutex。这是汤小丹教材反复强调的“资源在前互斥在后”。5.3 现象LRU 和 FIFO 算出来缺页次数一样原因引用串太短或物理块太多两种算法恰好表现一致。解决换一个引用串验证比如1,2,3,4,1,2,5,1,2,3,4,5物理块 3FIFO 缺页 9 次LRU 缺页 10 次差异就出来了。别因为一次巧合就怀疑自己算错。5.4 现象OPT 算法手算时把“未来最远”看成“未来最近”原因审题不清。OPT 淘汰的是未来最长时间不再访问的页不是最近要访问的页。解决在草稿纸上把未来引用串抄一遍对每个在内存中的页标注“下一次出现的位置”选位置最靠后或不再出现的淘汰。这个动作慢但准考场上别省。6. 用“错题反推”把课后题变成自己的知识图谱最后一章说一个我用了很多年的技巧不要按章节顺序刷汤小丹的课后题而是按“错题类型”反推知识漏洞。具体做法是准备一个表格三列题目编号、考的知识点、我错在哪。每做错一道就填一行。坚持两周你会发现自己的错误集中在某几个机制上——比如“信号量初值设错”或“页面置换表漏列”。然后针对这些机制回到教材对应小节重读再用第 2、3、4 章的脚本验证。下面是我当年整理的一张示例表题目来源知识点错误现象修正动作第 3 章 习题 12银行家算法Available 未更新用脚本逐步打印 Work第 4 章 习题 8PV 操作P 顺序反了重画资源视角图第 5 章 习题 6LRU命中未移末尾手算时用箭头标最近使用第 6 章 习题 3页面置换缺页率算错表格加累计行这个习惯的好处是你不再依赖“课后答案”的对错而是依赖自己的验证脚本和错题记录。汤小丹这本教材的课后题质量很高但答案版本鱼龙混杂我见过不少把 FIFO 和 LRU 结果写反的“参考答案”。与其赌答案对不对不如自己跑一遍脚本。我现在的习惯是每学完一章先手算两道典型题再用脚本验证最后把错题填进表格。希望帮到你。本文还有配套的精品资源点击获取
返回列表