这份课程资料我帮大家整理过一遍:CS537 是威斯康星大学麦迪逊分校的操作系统核心课,Fall 2019 版本用 OSTEP 当教材,配套实验、作业、考试原题全部能拿到。如果你正在自学操作系统、准备考研复试,或者在刷 OSTEP 想找配套练习,这套资源值得认真过一遍。
这次我们直接看威斯康星 CS537(Fall 2019)的完整课程体系,以及配套的 OSTEP 三件套到底怎么配合使用。先说结论:这不是一门“泛泛讲概念”的课,整门课围绕 OSTEP 教材展开,配了三个 C 语言实验项目,覆盖 xv6 内核修改、并发编程和文件系统实现,适合有一定 C 语言基础、想动手写内核代码的读者。
先给一份核心信息速览,再往下讲课程内容、实验安排、学习路径和常见问题。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 课程名称 | University of Wisconsin-Madison CS537: Introduction to Operating Systems |
| 开课学期 | Fall 2019 |
| 主讲人 | Andrea Arpaci-Dusseau 与 Remzi Arpaci-Dusseau |
| 使用教材 | OSTEP(Operating Systems: Three Easy Pieces) |
| 配套资源 | OSTEP 教材 + OSTEP 课后作业 + CS537 实验项目 |
| 实验平台 | xv6 教学操作系统(基于 Linux 环境) |
| 编程语言 | C 语言 |
| 实验数量 | 3 个大型实验项目(P1/P2/P3) |
| 资源形式 | 课程主页、教材 PDF、投影片、作业题、实验说明、考试题目 |
| 适合人群 | 自学者、学生党、备考考研复试、刷 OSTEP 的读者 |
| 是否免费 | 是,课程官网和 OSTEP 官网均可访问 |
| API/代码库 | 非软件项目,无 API;但实验代码是真实 C 工程 |
这个课程的设计思路和很多学校“纯讲 PPT”的操作系统课完全不同。CS537 的作业分为两大部分:一部分是 OSTEP 书中每章后面的“Homework”作业,另一部分是三个贯穿学期的实验项目。前者用来巩固概念,后者用来检验代码能力。
2. 适用场景与学习价值
2.1 适合什么人学
- 自学操作系统的同学:已经看完 OSTEP 前几章,但缺少练习,CS537 的作业和实验正好补齐。
- 准备考研复试的考生:操作系统是计算机考研复试高频科目,CS537 的覆盖范围贴近国内专业课大纲,而且实验题能展示真实项目能力。
- 代码基础一般,但想挑战内核开发:xv6 是专为教学设计的操作系统,代码量只有一万行左右,比 Linux 内核容易上手得多。
- 想在简历里加“操作系统实验”项目的人:三个实验做完,能写出清晰的项目描述和代码仓库。
2.2 能解决什么问题
很多人读 OSTEP 会有一个困惑:书看懂了,但不会写代码,也不知道内核里一个系统调用到底怎么从用户态走到内核态。CS537 的实验就是来解决这个问题的。P1 会让你修改 xv6 的调度器,P2 会让你实现并发数据结构,P3 会让你改动文件系统相关逻辑。做完之后,你对“进程调度”“并发同步”“文件系统布局”的理解会从“知道概念”变成“能写代码”。
2.3 不适合什么场景
- 完全没学过 C 语言,不建议直接开始。
- 只想看概念、不打算动手写代码,这套资源的效果会打折扣。
- 时间紧张、只想考前突击知识点,直接刷 OSTEP 和课程投影片更快,实验项目短期内做不完。
2.4 学习边界与合规提醒
这套课程资料是公开的教学资源,用于学习和研究没问题。实验代码需要自己完成,不要直接复制他人仓库提交到课程系统。另外,xv6 本身是 MIT 开源的教学系统,CS537 基于它做二次开发,实验说明也会标注来源。如果你把实验代码放到 GitHub,建议注明课程出处和参考来源,保持学术诚信。
3. 课程完整体系拆解
CS537 的课程体系设计思路很清晰:教材提供理论知识,投影片便于复习,作业检验理解,实验检验动手能力。
3.1 课程大纲覆盖范围
从 Fall 2019 的课程结构来看,核心模块包括:
- 进程与线程:进程抽象、线程模型、上下文切换。
- 调度算法:MLFQ(多级反馈队列)、轮转调度、比例份额调度。
- 同步原语:锁、条件变量、信号量、自旋锁。
- 死锁:死锁条件、银行家算法、实际系统中的死锁处理。
- 地址空间与虚拟内存:分页、页表、TLB、多级页表。
- 内存分配:buddy allocator、slab allocator、malloc 实现(实验可能涉及)。
- 文件系统:inode、目录结构、崩溃一致性、日志文件系统。
- I/O 与磁盘调度:设备驱动、DMA、调度算法。
- 虚拟化与容器基础:部分内容会涉及。
这些模块和 OSTEP 的章节一一对应,复习时可以按章节检索投影片。
3.2 课程主页与资源布局
课程主页结构通常包含:
- Syllabus:课程安排、评分标准、截止日期。
- Lectures:按日期排列的投影片。
- Readings:对应 OSTEP 章节。
- Homework:书后作业题目。
- Projects:三份实验说明。
- Exams:期中/期末试卷(含答案)。
建议把课程主页完整下载到本地,尤其是投影片和实验说明。有些同学在复习时会发现课程主页偶尔打不开,提前备份更稳妥。
3.3 OSTEP 教材版本说明
OSTEP 目前有两个常见版本:免费在线版和印刷版。Fall 2019 使用的章节以在线版为准。书的核心部分分为三大块:虚拟化(Virtualization)、并发(Concurrency)、持久性(Persistence),也就是“Three Easy Pieces”这个名字的来源。
读这本书时要注意,它和很多国内教材的知识点编排顺序不同。OSTEP 先用大量篇幅讲虚拟化,再进入并发,最后讲文件系统。建议跟着课程顺序读,而不是按自己过去的习惯重新排序,这样和作业、实验的衔接更顺。
4. OSTEP 三件套怎么配合使用
所谓“三件套”,是指 OSTEP 教材、OSTEP 课后作业、OSTEP 对应代码实验。三者是一个整体。
4.1 第一件:教材正文
读取方式是“先看问题,再看解答”。每章开头会抛出真实问题,比如“如何让一个程序看起来独占 CPU?”,然后逐步推导解决方案。这也是 CS537 上课的习惯:先给场景,再给机制。
示例:读调度器章节时,可以带着几个问题去读:
- 为什么需要抢占式调度?
- MLFQ 如何解决“只知道局部信息”的调度问题?
- 各调度算法的时间复杂度是多少?
读完后,去看对应的投影片,重点看老师怎么把书里的机制画成图。
4.2 第二件:课后作业
OSTEP 官网为每章准备了 Homework,很多是模拟程序。比如调度章节的scheduler.py是 Python 脚本,可以模拟各种调度算法的执行过程;分页章节的paging-policy.py可以模拟不同页面置换策略。
作业形式举例:
# 以 MLFQ 调度作业为例 python scheduler.py --sched mlfq --jlist 0,100,20,200,30,300 -q 10 -j 3 -n 3自己动手改参数、观察结果、和理论预测对比,能加深理解。CS537 的评分里,Homework 也占一定比重,要求提交答案和简短分析。
4.3 第三件:实验项目(Projects)
CS537 的实验项目是整套资源里最有价值的部分。Fall 2019 共有三个 Project,全部围绕 xv6 系统进行开发。
5. 三个实验项目解析
这是整套课程的重头戏。三个项目难度梯度明显:P1 偏简单,P2 进入并发编程,P3 深入到文件系统。
5.1 P1:xv6 系统调用与调度器
第一个项目通常会涉及给 xv6 增加系统调用,并实现一种新的调度策略。主要锻炼的是:
- 阅读内核代码的能力。
- 用户态和内核态的切换路径。
- 进程结构体
struct proc的字段含义。 - 调度器的基本结构。
常见的实现目标包括:
- 增加一个系统调用,比如
getpid_count()或其他自定义调用。 - 修改调度器,把默认的轮转调度改为优先级调度,或者实现 lottery scheduling(彩票调度)。
- 通过测试程序验证调度结果。
这部分的基础是理解 xv6 启动过程中main()如何初始化第一个进程,以及scheduler()如何在进程间切换。调试时可以加cprintf输出观察执行顺序。
5.2 P2:并发编程
第二个项目是纯用户态并发编程,不涉及内核修改。常用的题目形式是:
- 实现一个并发哈希表(concurrent hash table)。
- 实现一个并发队列或并发计数器。
- 使用 pthread 库和信号量/条件变量解决生产者消费者问题。
- 实现一个简单的读写锁。
这部分主要考察:
- 锁的粒度:粗粒度锁和细粒度锁的性能差异。
- 条件变量的使用。
- 无锁编程的基础(部分年份可能涉及)。
- 使用
-fsanitize=thread或 valgrind 排查数据竞争。
性能测试是关键。提交报告时通常要给出不同线程数下的吞吐量,分析锁竞争瓶颈。
5.3 P3:文件系统
第三个项目通常是文件系统相关。常见形式有:
- 在用户态模拟一个文件系统(FUSE 或独立模拟)。
- 修改 xv6 的文件系统代码,比如支持更大的文件、实现日志机制等。
- 实现磁盘块分配策略(顺序分配、索引分配等)的模拟。
这一部分要求理解 inode、目录项、超级块、块位图等概念。调试文件系统代码很容易“跑一遍就崩”,建议提前写好单元测试,并在修改关键数据结构时先画清楚磁盘布局。
5.4 实验评分标准参考
CS537 通常有一套自动评分脚本,测试程序会覆盖边界情况。比如调度实验会测试短任务和长任务混杂、进程退出、多核并发等场景。所以提交前一定要:
- 跑通官方提供的测试程序。
- 用自己的测试用例补充边界测试。
- 做性能和正确性的回归对比。
6. 学习路线与进度建议
根据课程安排(一般是 15 周),可以给自己排一个 12-16 周的复习计划。
6.1 第一阶段:OS 基础与 C 语言复习(第 1 周)
- 复习 C 语言指针、结构体、链表。
- 熟悉 Linux 命令行、gcc、gdb、make。
- 阅读 xv6 源码中的
proc.c、syscall.c、trap.c,不要求全部看懂,先建立整体结构印象。
# 克隆 xv6 源码(以 xv6-public 为例) git clone https://github.com/mit-pdos/xv6-public.git cd xv6-public make make qemu如果make qemu能进入 xv6 的 shell,说明环境已经准备好。
6.2 第二阶段:系统调用与调度(第 2-5 周)
对应 OSTEP 的虚拟化章节和 P1 实验。具体节奏:
- 读 OSTEP 第 4-7 章(进程、API、机制、调度)。
- 完成课后作业中的调度模拟。
- 通读 xv6 的
proc.c和syscall.c。 - 完成 P1。
注意:P1 是最适合“建立信心”的实验。它的代码量不大,但能让你掌握实验环境的调试方法。
6.3 第三阶段:并发与同步(第 6-9 周)
对应 OSTEP 并发章节和 P2 实验。
- 读 OSTEP 第 26-31 章。
- 写几个小的并发程序,比如并发计数器、并发队列。
- 用
helgrind或 TSAN 找数据竞争。 - 完成 P2。
这个阶段最容易踩的坑是死锁和条件变量丢失唤醒。建议给每个并发结构画清楚锁的顺序。
6.4 第四阶段:地址空间与文件系统(第 10-14 周)
对应 OSTEP 的虚拟内存和持久性章节,以及 P3 实验。
- 读 OSTEP 第 13-25 章(虚拟化部分)。
- 读 OSTEP 第 36-42 章(文件系统)。
- 做地址翻译模拟作业。
- 完成 P3。
P3 逻辑复杂,调试时间要预留充足,至少留两周以上。
7. 使用环境与工具链
虽然这不是软件产品,但做实验需要完整的环境配置。
7.1 推荐环境
| 项目 | 推荐配置 |
|---|---|
| 操作系统 | Linux(Ubuntu 20.04/22.04 或 Debian) |
| CPU | 任意 x86_64 架构均可 |
| 内存 | 4GB 以上 |
| 磁盘 | 10GB 空闲空间 |
| 编译器 | gcc、gdb、make |
| 虚拟机 | QEMU |
| 其他工具 | git、python3(用于部分作业模拟脚本) |
7.2 xv6 环境搭建
xv6 的经典版本基于 x86,新版本基于 RISC-V。CS537 Fall 2019 使用的是早期的 x86 版本,构建相对简单:
sudo apt-get update sudo apt-get install -y build-essential gdb qemu-system-x86 git python3 git clone https://github.com/mit-pdos/xv6-public.git cd xv6-public make make qemu如果启动 QEMU 时提示缺少图形界面,可以改成:
make qemu-nox这样会以纯终端模式启动 xv6,适合 SSH 环境。
7.3 调试工具使用
xv6 的调试通常依赖 gdb 和 QEMU 的调试端口。启动调试模式:
make qemu-gdb然后在另一个终端进入 gdb:
gdb kernel target remote localhost:26000 break scheduler continue这个调试方式对 P1 调度器实验特别有用。
8. 资源获取与备份建议
获取整套课程资源时,建议采用分层策略:
- 课程主页:直接下载所有投影片 PDF。
- OSTEP 官网:下载教材 PDF 和 Homework 说明。
- 实验代码模板:如果有官方模板,直接克隆仓库。
- 笔记与复习资料:自己整理或参考 GitHub 上公开的笔记。
注意不要直接把别人的实验代码提交到课程系统,这会涉及学术诚信问题。自己的学习笔记和代码仓库可以公开,但要标注出处。
9. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
make qemu启动后黑屏 | 图形界面不支持 | 改用make qemu-nox | 以纯终端模式运行 |
编译报错undefined reference to ... | 系统调用未添加到syscall.h或sysproc.c | 检查系统调用注册流程 | 补充函数声明和系统调用号 |
| 调度器运行后进程卡死 | 没有正确调用yield() | 加cprintf跟踪 | 检查调度循环里的进程状态切换 |
| 并发程序偶尔出现错误结果 | 数据竞争 | 用 TSAN 或 helgrind 检测 | 调整锁粒度或增加同步 |
| P3 文件系统测试崩溃 | 磁盘块分配逻辑错误 | 打印 inode 和块位图 | 先画出磁盘布局,再改代码 |
| 课程主页无法访问 | 网络问题或原页面调整 | 使用 Wayback Machine 或本地备份 | 提前保存 PDF |
| 作业模拟脚本无法运行 | Python 版本不兼容 | 查看脚本头部注释 | 安装对应 Python 版本并安装依赖 |
| 实验报告提交格式不对 | 没有按说明命名 | 查看提交说明 | 重新命名打包 |
10. 最佳实践与学习建议
结合自学的实际经验,整理几条实用建议:
10.1 第一周先跑通 xv6
不要急着写代码,先把 xv6 跑起来,随便用 shell 执行几个命令,感受一下教学操作系统的结构。然后花一天时间通读README、Makefile和kernel/proc.c(或对应目录)。这一步能省下后面大量排错时间。
10.2 每个实验先画图再写代码
P1 画进程状态机,P2 画锁顺序图,P3 画磁盘布局图。画图的过程就是理清逻辑的过程,大部分调试困难都来自“没想清楚就动手”。
10.3 建立自己的测试清单
自动评分脚本测试的是边界,比如:
- 进程数量为 0 或 1 的情况。
- 高并发下同步结构是否稳定。
- 文件系统写入大量小文件。
建议在写正式代码前,先列一份测试清单,每个功能点对应至少一个测试用例。
10.4 用 Git 管理实验代码
每个实验单独建仓库,每个关键节点打 commit。碰到实验改了代码不工作,可以快速回退,再对比差异定位问题。
10.5 保留一份实验报告模板
CS537 的实验报告通常要求包含:设计思路、关键代码说明、测试结果、遇到的问题。提前写报告,比最后一天补要轻松得多。报告本身就是面试时可以展示的项目材料。
11. 总结与下一步
CS537 Fall 2019 是一套质量很高的操作系统学习资源。它的价值不在于投影片多华丽,而在于“教材—作业—实验—考试”形成了一个完整闭环。按 OSTEP 章节顺序学知识点,用 Homework 做验证,再用 xv6 实验把能力落到实处,这条路径比单纯刷书更能建立真实的操作系统工程能力。
最先应该做的三件事:
- 下载 OSTEP 教材 PDF 和课程投影片,并通读前五章。
- 搭建 xv6 环境,跑通
make qemu-nox。 - 做完第一个课后作业(调度模拟),感受一下 OSTEP 作业的形式。
最容易踩的三个坑:
- 跳过 C 语言复习直接写实验,代码能力跟不上。
- 只读教材不动手,遇到实验完全没思路。
- 不做测试就直接提交,被自动评分脚本扣分。
如果你已经完成了 CS537 的 P1 实验,下一步可以尝试把 P2、P3 一并做完,然后对比 MIT 6.S081 的实验题,两者侧重点不同,CS537 偏传统 OS 机制,6.S081 偏现代 OS 工程。两个都做一遍,操作系统这关基本就稳了。建议收藏这篇文章,需要时照着搭建环境、规划学习节奏。