ARTICLE DETAIL

资讯详情

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

从背概念到写系统:CS537与OSTEP操作系统自学路线指南

从背概念到写系统:CS537与OSTEP操作系统自学路线指南 威斯康星麦迪逊的CS537操作系统课搭配该校Remzi教授团队编写的免费教材OSTEP是一套很适合用来把操作系统从“背概念”推进到“写系统”的学习组合。很多人学操作系统都有这样的经历进程、线程、虚拟内存、文件系统这些名词都认识面试也能答出几个但一让你写一个调度算法、改一个锁的行为、解释一次页表的地址转换过程整个人就卡住了。CS537的核心价值就是把这一块短板补上OSTEP则提供了原理阅读、课后作业和实验项目的完整路径。如果你准备考研复试、准备校招基础或者就是想把计算机系统基础再打扎实一点这个名字值得你认真看一眼。下面我按自己的学习路径把课程、教材、项目、中英双语学习这四块拆开讲尽量写成可以直接照着执行的路线而不是只列一份资源清单。1. 威斯康星CS537和OSTEP为什么值得系统学一遍1.1 这门课解决的典型问题概念全会代码全废操作系统是计算机专业课里比较特殊的一门。它不像数据结构那样上手就能写链表也不像计算机网络那样可以抓包看协议。操作系统讲的是进程调度、内存管理、并发同步、文件系统这些内容平时在使用电脑时根本摸不到。大多数人学完一遍操作系统课只留下几个名词比如PCB、LRU、信号量、inode但要说出它们在真实代码里怎么体现就说不清楚了。CS537这门课解决的正是这个问题。它是面向本科生开设的系统入门课程核心不是带你读教材而是让你在真实的操作系统场景里把概念实现一遍。课程项目会涉及线程库、调度器、内存管理、锁和文件系统相关内容学生要做的是读源码、改代码、看行为、验证结果。这个训练过程非常接近工业界做系统软件的方式。这里要说明一点不同学期的CS537项目细节可能不一样不一定每个学期都完全一致。所以不用纠结“是不是xv6”“是不是某个具体教学系统”重点在于课程安排了“阅读、修改、运行、调试”这一整套没有打折扣的实操流程。这个流程才是操作系统学习里最值钱的部分。1.2 为什么免费教材和公开课程适合自学OSTEP全称是Operating Systems: Three Easy Pieces中文通常翻译成《操作系统导论》。这本书由威斯康星大学麦迪逊分校的Remzi教授等人编写网上可以直接获取原版内容。它的特点是讲原理但不堆术语每个章节都有对应的代码例子和课后作业阅读体验比很多传统教材轻松。很多操作系统教材适合当字典查但不适合从头到尾读。因为它们概念全面、体系庞大初学者很容易迷失在细节里。OSTEP不一样它把内容按“虚拟化、并发、持久化”三大块重新组织每个模块相对独立可以先读虚拟化了解进程和内存再读并发了解线程和锁最后读持久化了解文件和磁盘。这种结构天然适合自学。CS537和OSTEP的关系是课件、作业和考试逻辑以OSTEP为主线再配上课程项目。所以你不需要自己在海量资料里挑挑拣拣只要跟着课程节奏走就行。这也是我推荐从Fall 2019这学期开始的原因课程时间虽然早了一点但操作系统核心知识变化不大这一期的录像和配套资料比较完整作为入门非常合适。2. OSTEP三件套分别指什么怎样搭配使用2.1 OSTEP教材虚拟化、并发、持久化三块主线OSTEP把操作系统主要功能分成三部分这个分法非常值得记下来。第一部分是虚拟化。CPU被抽象成进程内存被抽象成地址空间底层用上下文切换、调度算法、页表、TLB、交换空间等机制实现抽象。学完这一块你能回答“进程和线程有什么不一样”“为什么虚拟内存能让一个程序以为内存很大”这类问题。第二部分是并发。多个执行流同时访问共享数据时会出现竞态条件、原子性问题。锁、信号量、条件变量、读者写者问题都在这一部分。这块是操作系统里最容易写错代码的部分也是面试常考的点。第三部分是持久化。数据不能只停留在内存里需要写到磁盘和文件系统。文件和目录怎么组织、磁盘调度怎么做、崩溃之后怎么保证数据不损坏这部分会讲。学习时要特别注意“崩溃一致性”问题它是文件系统实验里最常见的难点。我自己读这本书时有个很直观的感受它不是上来就讲Linux某段实现而是先告诉你一个机制解决什么问题再给一个简化例子最后才回到真实系统。这种“从需求到实现”的写法对自学者特别友好。2.2 授课视频和幻灯片负责把节奏带起来只看书容易有两个问题一是不知道每章重点在哪里二是遇到复杂的图不知道怎么动起来。授课视频的作用是给学习节奏划定边界。视频里老师会花大部分时间讲关键推导和代码示例很多东西比看书更直觉。我的建议是不要用视频替代阅读而是让视频做“导读”。每学一个章节前先看对应的课程视频知道这一章要解决什么问题然后回到OSTEP教材逐段读书最后再根据视频中提到的小作业、模拟题去跑一跑。这样一轮下来知识会经过“听、读、做”三遍处理记忆要牢固得多。Fall 2019的课程视频是全英文的如果英文听起来吃力先把幻灯片和教材配合着看遇到不理解的地方再回看视频片段。不要试图一次把所有视频看完那和刷剧没有区别。2.3 配套项目和作业让原理变成可运行代码操作系统课最核心的训练在项目里。OSTEP教材每章后面都有“作业”或“项目”部分有的要求你写模拟程序有的要求你在小型教学系统上实现某个功能。CS537的项目也是同样思路。学到这里要有一个心理准备项目学起来比读书慢但也只有慢下来才能真正理解系统。比如调度器实验你要写一个调度算法需要处理进程到达时间、执行时间、时间片切换、等待时间等变量。这些变量在书里只是公式在代码里是真实数据结构。写完你会明白为什么调度算法不能只看“平均等待时间最短”还要考虑优先级反转、响应时间和公平性。注意不要一上来就打算把整个实验全部跑完。第一遍先用最小样例确认环境能编译、能启动、能输出日志再往下一步走。很多项目做不下去不是因为代码难而是因为基础路径没有先打通过一遍。3. 跟学之前先把最小环境准备好3.1 选Linux环境虚拟机、WSL还是物理机操作系统的系统编程实验最好在Linux环境下做。如果你的电脑本身就是Linux那最省事。如果主力机是Windows常见选择有两个虚拟机里装一个Linux或者使用Windows Subsystem for LinuxWSL。虚拟机的好处是环境隔离比较干净网络、磁盘、内核都完全独立适合做需要修改内核配置或观察系统行为的实验。缺点是需要额外分配内存和磁盘启动要等一会儿。WSL的启动更快、文件访问更方便但部分实验对系统底层访问有要求WSL的兼容性不一定完全满足。我的建议是如果电脑内存不低于8GB优先用虚拟机装一个完整Linux发行版如果只是看视频、记笔记、跑普通C程序WSL也够用。另外一个现代趋势是使用容器来做实验环境比如Docker里映射一块开发目录编译和运行都在容器内。容器适合做“标准工具链统一”的场景但如果你要修改内核代码或者做系统调用追踪容器受限会比较多。所以刚开始不要太依赖容器先把传统环境跑熟。3.2 工具链和资源底线不管选哪种环境需要准备的最小组件是这几个工具作用说明gcc 或 clangC/C编译器系统实验基本用C语言编译器必须可用make构建工具项目通常用Makefile组织编译手动逐个gcc不方便gdb调试器排查段错误、死锁、逻辑错误时会频繁使用git版本管理每次实验改动前先提交一次方便回退top / htop查看资源占用程序卡住时先看CPU和内存变化而不是乱猜vim / VS Code编辑代码只要能改代码就行不限制编辑器配置完这些之后可以先在终端里确认一遍gcc --version make --version gdb --version git --version如果每条命令都输出版本信息说明基础工具链可用。这一步看起来简单但很多实验跑不起来都是因为编译器版本太旧、没有安装make或者PATH里找不到命令。在资源方面学习阶段的底线不需要太高。内存4GB以上就能跑大部分模拟实验磁盘预留20GB足够安装系统和编译缓存。但如果要做编译Linux内核级别的修改内存最好8GB以上磁盘需要30GB以上。这里给的是通用范围具体以你的实验要求为准。3.3 目录结构和备份习惯操作系统课程内容多如果所有代码都堆在桌面上很快就会乱。建议按章节建立目录例如ostep/ ├── 01-process-vm/ ├── 02-concurrency/ └── 03-persistence/每个实验里先把原始代码复制一份到backup目录或者用git打一个tag。因为实验经常要修改底层模块改坏之后如果靠记忆恢复非常浪费时间。先提交一次原始版本后续改动都记录在git里能随时看到“改了什么导致行为变化”。不要小看这个习惯。我见过太多人实验做到一半代码面目全非最后只能从头再拉一遍。备份不是浪费时间是给后面所有调试省时间。4. 单讲概念容易空用配套项目把知识落到代码里4.1 拿到实验先做最小闭环任何一个实验项目不要急着看完整需求再动手。第一件事是先把它跑起来看到最初版本的输出。比如一个调度模拟实验原始代码可能已经能编译只是输出一组默认结果。你要先确认自己能复现这个默认输出然后再去改逻辑。这个“最小闭环”思路非常重要。操作系统实验往往代码量不大但涉及系统状态和异步过程如果一开始就大改出了问题很难判断是逻辑错、环境错还是原来的代码就依赖某种条件。先跑通原始版本相当于给后续所有改动打一个基线。跑通原始版本后可以尝试一个非常小的改动比如修改一个输入参数、调整一个数组长度重新编译运行观察结果是否有变化。这样可以验证“代码改动到结果输出”这条链路是通的。4.2 以调度模拟为例看实验该怎么拆调度器是操作系统课里最常见的实验之一。这类实验通常会给你一批进程每个进程有到达时间、执行时间、优先级等参数要求你实现FIFO、SJF、Round Robin等调度算法并输出每个进程的完成时间、等待时间、周转时间。这类实验适合拆成三步来做第一步先解析输入。不管输入是文件、命令行参数还是结构体数组先确认数据读进来之后能正确打印。第二步先只实现一种最简单的算法比如FIFO。因为FIFO逻辑最简单你可以手工算出预期结果再用程序跑一遍对比是否一致。这一步通过之后再实现Round Robin等更复杂的算法。第三步统一封装输出格式。很多实验有评分脚本会按照固定的输出格式判断结果正确性。所以输出字段的顺序、小数位数、换行符都需要提前确认。下面用伪代码描述一轮调度模拟的基本流程方便你理解这类实验的骨架。这不是课程原代码只是用来帮你把实验想象出来// 调度模拟器伪代码不是课程原代码 while (time total_time) { add_arrived_processes_to_queue(ready_queue, time); current pick_next_by_algorithm(ready_queue, policy); run_for_one_slice(current, time_slice); if (current-remaining 0) { record_completion(current, time); } time 1; }写这类代码时最容易犯的错误是只关注“选下一个进程”的算法忽略“时间推进”和“进程到达”的逻辑。实际很多调度实现bug出在时间推进的顺序上而不是调度策略本身。4.3 验证结果的三条判断标准实验做完了怎么判断真的做对了我一般看三件事。第一输出是否符合预期。不是“看起来差不多”而是每个字段都和手工算出来的一致或者在允许误差范围内。第二边界输入是否处理。进程数很多、执行时间很小、所有进程同时到达、没有进程到达这些边界情况如果程序能正常跑完说明逻辑比较稳。第三结果是否可重复。同样的输入连续运行三次如果输出不一致说明可能有未初始化的变量、随机因素或者竞态条件。系统实验里结果不稳定比结果错误更麻烦因为它说明程序内部状态不可控。5. 中英双语学习别让英文成为半途而废的理由5.1 先把核心术语的英文原文记牢CS537的视频、教材和实验文档都以英文为主。很多人在看英文资料时最大的障碍不是语法而是术语不通。看一句“the process moves from ready to running”时你如果能立刻对应“进程从就绪态进入运行态”这句话就不难。所以我建议每学一章之前先把这一章的核心名词英文对照过一遍。这里列一组操作系统最常用的术语对照后面会反复出现英文中文备注process进程运行中的程序实例thread线程进程内的执行流schedule / scheduler调度 / 调度器决定谁占用CPUcontext switch上下文切换切换执行流时的状态保存与恢复virtual memory虚拟内存对内存地址的抽象page table页表虚拟地址到物理地址的映射结构mutex / lock互斥锁 / 锁保护临界区condition variable条件变量线程间等待与通知deadlock死锁多个执行流互相等待file system文件系统管理持久化数据的结构inode索引节点文件元数据存储单元这些词的英文拼写不需要一次性全背完但每学到一个概念就把对应英文写进笔记里。看源码时报错、查文档、搜资料时会舒服很多。5.2 用“读一段、跑一个、写一点”代替整段翻译学英文教材最忌讳整段整段翻译。翻译会让人产生“我读懂了”的错觉但过几天回忆时只记得中文不记得原理。更有效的方式是“读一段、跑一个、写一点”。读教材中的一个章节段落然后马上做一个对应的模拟实验最后用自己的话写三五行总结。如果你能用自己的语言把这一段的逻辑复述清楚并且实验输出和预期一致这个知识点才算真正接住了。具体到操作每学完一个章节不要急着开下一个。停一下打开终端把书里提到的模拟程序跑一遍改两个参数看看结果变化。没有代码的实验章节就自己画一个示意图把关键流程标出来。这个习惯比单纯多读一遍书有用。5.3 什么时候再看中译本和资料中译本和中文资料适合用来建立整体轮廓或者在英文原文卡住时作为辅助。比如一个章节涉及很多背景概念你可以先花20分钟看中文资料知道大概在讲什么再回到英文原文精读。但不要从头到尾只读中译本。原因很简单很多系统名词的中文翻译不统一不同书里可能叫法不同而代码、报错、文档、面试题往往直接使用英文。如果你只熟悉中文术语一旦进入真实生产环境还是会重新适应一次。最好的状态是“中英文都能说看到英文能反应出中文看到中文能联想到英文”。如果英语基础比较弱还有一个办法把教材的PDF导入笔记软件先只阅读每章的“关键概念”和“代码示例”部分正文可以后期再看。这样能快速抓住每章主干不会被冗长的英文描述拖累。6. 常见报错和排查顺序从启动到验收6.1 编译不过先看第一行而不是最后一行编译报错时新手经常翻到最后看最后一条错误其实这样做往往事倍功半。编译错误的第一行通常指出真正的缺失或语法问题后面的报错可能是连锁反应。比如某个头文件缺失导致后面几十个类型不识别如果你从最后一个错误开始排查就会陷入无意义的修改。正确的顺序是看第一行报错确认文件路径和行号。看报错类型是未定义引用、头文件缺失、语法错误还是类型不匹配。如果报错涉及外部库检查是否安装依赖或编译命令里是否缺少链接参数。修复后重新编译而不是一次性修改多个问题。如果是链接错误比如出现undefined reference优先怀疑是缺少某个库或者函数签名不匹配。这种情况下多检查Makefile里的链接参数和依赖顺序。6.2 启动失败优先检查权限、路径和依赖代码编译通过不等于程序能正常启动。启动阶段失败常见的几个原因运行目录不对程序找不到输入文件或配置文件。当前用户没有读写某个目录的权限。缺少动态运行库运行时报库找不到。程序要求的端口、文件或设备被其他进程占用。排查时先确认启动时的工作目录。很多实验程序依赖相对路径读取文件如果你在另一个目录下调用它路径就对不上。然后把报错信息完整贴到搜索引擎里看是否有人遇到过同样问题。比盲目尝试更高效的方法是用strace或ldd查看系统调用和依赖但新手阶段更推荐先确认路径和权限这两个原因占比最高。6.3 跑起来但结果不对优先缩小输入规模程序能跑但输出和预期不一致这是实验后期最常遇到的情况。此时不要急着调整整个逻辑也不要不断改参数。先构造一个极小的输入比如两个进程、三个操作手工算出预期结果再让程序执行。如果小规模输入下结果正确再逐步增加规模看问题从哪一步开始出现。如果小规模输入下结果已经不正确那就用调试器在关键位置打断点逐步看变量变化。这里要特别提醒判断结果对不对必须回到实验说明给出的标准而不是“好像符合直觉”。有的实验对输出精度有要求有的对进程状态定义有特殊说明如果按自己的理解去判对错很容易在一个错误前提下花很长时间调试。6.4 程序卡住或崩溃先看资源再猜原因程序卡住是系统编程里最让人头疼的问题之一。卡住不等于死锁也可能是死循环、等待输入、等待某个事件或者资源竞争导致进度停滞。排查顺序我一般是这样先用top或htop看进程的CPU和内存占用。CPU占用接近100%但一直不结束大概率是死循环需要看代码里哪些循环条件可能不退出。CPU占用很低、进程一直不结束多半在等待某个资源比如锁、网络、文件、子进程退出。内存持续增长可能是内存泄漏需要检查每轮循环里是否有释放不及时的问题。如果程序直接崩溃先看dmesg或日志确认是不是段错误、栈溢出、非法内存访问。在实验环境中我会同时开着终端和资源监视器当程序异常时能立刻看到资源变化。先看资源再结合代码猜原因可以省去大量毫无头绪的排查时间。7. 我建议的学习周期和落地方法7.1 按章节推进不按播放进度推进有些同学喜欢一口气把课程视频都下下来按播放列表顺序看。看视频确实轻松但到实验环节还是会卡住。我更建议按知识章节推进每周处理一个OSTEP大章节对应的内容。一个保守但容易坚持的节奏是周次学习内容配套动作第1周进程、进程API、地址空间跑进程创建示例观察内存布局第2周CPU调度、多级反馈队列实现简单调度模拟对比调度算法输出第3周地址转换、分页、TLB做页表换算练习运行地址转换模拟第4周线程、互斥、锁、条件变量写一个多线程计数器观察竞态条件第5周死锁、信号量、并发问题实现经典同步问题比如生产者消费者第6周文件系统、磁盘、崩溃一致性做完文件系统相关模拟理解inode和日志这只是一个示例实际进度可以根据自己的空余时间调整。重点是“一个章节没有跑完代码不要急着进入下一个章节”。操作系统知识是层层叠加的前面没磨透后面会一直返工。7.2 每个章节结束时留三个产出学完一章之后不要只说“我学完了”而是留下三个可以检查的东西。第一个是笔记。不是抄书而是用自己的话写这一章解决了什么问题、有哪些关键概念。可以画图可以写伪代码形式不限。第二个是实验记录。至少保存一个可以复现实验的命令比如make clean make ./scheduler input.txt --policy fifo这条命令要保证在干净环境里能够跑通输出结果可预期。第三个是“踩坑记录”。写下这一章里你犯过的错误比如“忘了处理进程同时到达的情况”“锁的范围写大了导致并发度下降”“页表计算时没把偏移量位数算对”。这些记录以后复习时比任何教材都好用。7.3 卡住怎么办降级输入、看资料、做记录如果某个实验连续卡了两三天不要死磕。降级输入是一个很有用的策略把进程数量减少、并发线程减少、文件大小缩小先用最小规模把逻辑跑通然后再恢复完整场景。如果降级后还是不行就把问题记录下来搜索报错信息或者把代码放一边回去重读教材相关章节。很多操作系统问题依赖前置知识可能你当前不理解的某个概念正好是几天后课程内容的铺垫。暂时跳过不代表放弃过一个月回头再看往往有新的理解。但要注意这里的“跳过”不是绕过整个实验而是暂时搁置细节继续往前走。最终还是要回到那个问题把它解决掉。操作系统学习最忌讳的点是看视频一时爽做实验一直拖最后只留下一个大概印象代码能力没有任何提升。这篇写下来我希望你最记住的不是“某门课很好”这个结论而是那条路径先准备能编译的Linux环境再按章节把概念和实验配对推进遇到问题时先看日志、资源和输入而不是急着改参数。OSTEP和CS537这套组合能不能帮到你取决于你有没有真的把每个大章节后面的代码和实验跑通。把概念落到代码里之后操作系统的知识才真正开始属于你。
返回列表