资讯详情

操作系统实验报告写作指南:从fork到信号量,掌握核心实验设计

📅 2026/10/12 21:56:58 | 华诺云谱 👁 阅读
操作系统实验报告写作指南:从fork到信号量,掌握核心实验设计
简介广东工业大学计算机学院操作系统课程实验报告合集由10级计科专业学生完成面向高校计算机专业学生和操作系统自学者。报告覆盖进程调度、作业调度、可变式分区存储管理与简单文件系统四个核心实验从进程控制块PCB设计、优先数抢占调度到分区分配与文件目录管理均有完整代码与调试过程。其中进程调度实验采用最高优先数优先和先来先服务两种算法每个进程运行一个时间片后若未结束则降低优先数重新入队每次调度输出就绪队列及各进程PCB信息清晰展示算法调度轨迹。作业调度与可变式分区分配实验分别关注后台作业调入内存和动态分区管理策略文件系统实验则演示文件的创建、读写与删除操作。资源打包为单个doc文档仅694KB目前已有1277人学习浏览适合实验报告参考、复试答辩准备或系统学习操作系统核心机制时使用。1. 操作系统实验报告从抄到懂这份资源能帮你少走一半弯路操作系统实验是很多计算机专业学生又爱又恨的一门课。爱的是终于能亲手写进程、调线程、看内存分配恨的是实验报告格式要求多、代码量不小、运行结果截图对不齐、总结写得像流水账。我当初做这门课实验时光是一个进程同步的Peterson算法就调了整整两个晚上第二天还要面对导师对“临界区到底在哪”的灵魂拷问。如果你也在为操作系统实验报告发愁——不知道报告结构怎么搭、不知道代码注释写到什么程度、不知道实验总结该怎么提炼那这份4份全的某高校操作系统实验报告合集就是为你准备的。它不只是一堆能抄的文字更是一套能帮你理解实验设计逻辑、快速上手的参考模板。适合正在修操作系统课、需要交实验报告、或者想提前看看实验长什么样的同学。2. 实验报告里到底该写什么四个实验模块与报告结构拆解2.1 进程管理实验fork() 之后的世界进程管理实验通常是操作系统课程的第一个动手环节。大多数学校的实验要求是用 fork() 创建子进程观察进程的 PID、父子关系以及并发执行时的输出交错现象。看似简单但报告里要写清楚的东西远比代码本身多。一份合格的进程管理实验报告至少包含实验目的别直接抄实验指导书用几句话概括你要验证什么、实验环境操作系统版本、编译器、机器架构、实验步骤每一步做了什么、观察到了什么、核心代码关键片段即可不用贴全部源码、实验结果与分析截图 对输出结果逐行解读、实验总结踩了什么坑、对进程概念有了什么新的理解。代码部分我建议贴这样的关键片段#include stdio.h #include unistd.h #include sys/wait.h int main() { pid_t pid fork(); if (pid 0) { perror(fork failed); return 1; } else if (pid 0) { printf(子进程: PID%d, 父进程PID%d\n, getpid(), getppid()); } else { printf(父进程: PID%d, 创建的子进程PID%d\n, getpid(), pid); wait(NULL); // 等待子进程结束避免僵尸进程 printf(子进程已回收\n); } return 0; }这段代码里有两个值得在报告中展开的点一是 fork() 的返回值在父子进程中不一样父进程拿到的是子进程 PID子进程拿到的是 0二是 wait() 函数的作用——如果不调用 wait() 或 waitpid()子进程结束时会变成僵尸进程这在后续内存管理的实验里会是一个很好的对比素材。报告里如果能写出“本次实验观察到子进程先于父进程结束但未回收时进程表中出现僵尸状态”就已经超出了普通学生的水平。2.2 内存管理实验从连续分配到页式管理的参数对比内存管理实验一般分两档基础档是模拟首次适应算法和最佳适应算法对内存分区进行分配和回收进阶档是模拟页式管理中的地址转换过程包括页号计算、页内偏移、缺页中断处理。大部分学校要求的是基础档但报告里如果能对两种算法做数据对比会明显加分。这里有一个常见做法是固定一组内存空闲分区分别用首次适应和最佳适应跑一遍同一串内存请求对比分配结果和碎片情况。# 模拟内存分区分配首次适应 vs 最佳适应 free_blocks [100, 500, 200, 300, 600] # 空闲分区大小 requests [150, 250, 200, 100, 400] # 请求序列 def first_fit(blocks, req): for i, b in enumerate(blocks): if b req: blocks[i] - req return i return -1 def best_fit(blocks, req): candidates [(i, b) for i, b in enumerate(blocks) if b req] if not candidates: return -1 i, _ min(candidates, keylambda x: x[1]) blocks[i] - req return i # 分别模拟并观察剩余空闲分区 blocks_ff free_blocks[:] blocks_bf free_blocks[:] for req in requests: first_fit(blocks_ff, req) best_fit(blocks_bf, req) print(首次适应剩余分区:, blocks_ff) print(最佳适应剩余分区:, blocks_bf)跑完这段模拟后报告里可以对比两组剩余分区的碎片化程度。最佳适应算法理论上会留下更小的碎片但在某些请求序列下未必比首次适应更优——比如当大请求到来时首次适应可能还保留着大块连续空间。这种“理论最优不一定实际最优”的观察恰恰是实验报告最值钱的部分。把两次运行的结果截到报告里再写一段对比分析这一章就立住了。3. 文件系统实验inode 与目录项的关系这样讲才清晰3.1 从 stat 命令到硬链接的本质文件系统实验常见的有两类一类是模拟实现简单的文件系统比如用数组模拟磁盘块、用位图管理空闲空间另一类是直接在 Linux 系统上观察文件系统的行为比如用 stat、ln、mount 等命令查看文件元数据和链接关系。大多数学校选后者因为实现一个真文件系统对本科生来说工作量太大课程设计阶段才会做。我比较推荐在报告里把 stat 命令的输出和 inode 的概念结合起来写。stat 能看到文件的 inode 编号、权限、链接数、大小、时间戳但很多同学只截了个图就完事了。真正该做的是先创建两个硬链接stat 观察链接数变化再删除其中一个再看链接数变化最后在报告里解释为什么链接数减一但文件数据还在。常见操作步骤是这样的echo hello os lab testfile.txt # 创建普通文件 ln testfile.txt testfile_hard1 # 创建硬链接 ln testfile.txt testfile_hard2 # 再创建一个硬链接 stat testfile.txt # 观察 st_nlink 字段 rm testfile.txt # 删除原文件 cat testfile_hard1 # 数据仍然可访问报告里要写清楚的核心结论是硬链接本质上是多个目录项指向同一个 inode所以删除其中一个名字时只要 inode 的引用计数不为零数据块就不会被释放。这个理解如果能写进报告导师一看就知道你真的做过实验而不是抄的。3.2 空闲空间管理位图法的参数与边界条件如果实验要求是写一个模拟的文件系统分配器位图法是最常见的实现方案。用一串二进制位表示磁盘块是否被占用0 表示空闲1 表示已分配。分配时找连续为 0 的位段释放时把对应位清零。关键是位图的大小计算和边界处理。// 用整型数组模拟位图每个 int 管 32 个块 #define BLOCK_COUNT 1024 #define BITMAP_SIZE (BLOCK_COUNT / 32) unsigned int bitmap[BITMAP_SIZE]; // 分配一个数据块返回块号失败返回 -1 int allocate_block() { for (int i 0; i BITMAP_SIZE; i) { if (bitmap[i] ! 0xFFFFFFFF) { // 不是全满 for (int j 0; j 32; j) { if (!(bitmap[i] (1 j))) { bitmap[i] | (1 j); return i * 32 j; } } } } return -1; } // 释放数据块 void free_block(int block_num) { int idx block_num / 32; int offset block_num % 32; bitmap[idx] ~(1 offset); }这里有个容易翻车的细节block_num 从 0 还是从 1 开始编号直接影响到位图索引的计算。我见过不少同学的代码里把 0 号块当作有效的可分配块结果位图的第 0 位被占用后后续索引全部错位。报告里如果能把“块号从 0 开始位图第 n 位对应块号 n”这个约定写明白再说明分配失败时返回 -1 的约定这部分的逻辑就完整了。4. 同步互斥实验信号量用不对程序就卡死在这三种现象里4.1 经典生产者-消费者模型的实验设计同步互斥实验是操作系统实验里 Bug 率最高的一节。表面上看就是 P 操作和 V 操作但真跑起来问题一堆。最常见的设计是用三个信号量mutex 管缓冲区互斥、empty 管空位数量、full 管数据数量。缓冲区大小设为 5 或 10生产者随机睡眠一段时间后往缓冲区放数据消费者类似地从缓冲区取数据。实验报告里的核心代码长这样sem_t mutex, empty, full; #define BUFFER_SIZE 5 void *producer(void *arg) { for (int i 0; i 10; i) { sem_wait(empty); // 申请一个空位 sem_wait(mutex); // 进入临界区 // 写入缓冲区 buffer[in] i; in (in 1) % BUFFER_SIZE; sem_post(mutex); // 离开临界区 sem_post(full); // 数据数量加一 printf(生产者生产: %d\n, i); usleep(rand() % 100000); } return NULL; } void *consumer(void *arg) { for (int i 0; i 10; i) { sem_wait(full); // 申请一个数据 sem_wait(mutex); // 进入临界区 int item buffer[out]; out (out 1) % BUFFER_SIZE; sem_post(mutex); // 离开临界区 sem_post(empty); // 空位数量加一 printf(消费者消费: %d\n, item); usleep(rand() % 100000); } return NULL; }我特别推荐大家在报告中指出信号量操作顺序的意义必须先 wait 资源信号量empty 或 full再 wait 互斥锁。如果反过来先拿 mutex 再等资源信号量当缓冲区满时生产者拿着 mutex 在等 empty消费者需要 mutex 但被占着两边互相等待直接死锁。报告里把这两行代码的先后顺序单独拎出来分析这页就是你自己写的分析不是抄来的。4.2 实验现象记录死锁、饥饿与忙等待同步互斥实验报告里实验结果部分除了正常输出最好再加上异常情况的观察记录。一个合格的实验报告会包含以下三种现象第一进程卡死。现象是程序运行后长时间无输出CtrlC 强制结束。原因是消费者线程在 empty 信号量为 0 时仍在等待可能因为初始信号量设置反了比如把 empty 初始化为 0、full 初始化为 5也可能是缓冲区空闲位置和实际情况不匹配。第二输出顺序错乱。现象是多个生产者或消费者的输出交错在一起出现“生产: 3 生产: 4 消费: 5”这种不合理的顺序。原因是临界区内有 printf 或 printf 放在了 mutex 外面导致输出操作没有受到保护。第三忙等待消耗 CPU。现象是程序能跑但 CPU 占用率到百分之百风扇狂转。原因是代码里用了“while(cnt BUFFER_SIZE);”这种自旋方式等待而不是用 sem_wait 挂起自己。在实验报告里对比自旋等待和信号量等待的 CPU 占用率属于高阶观察点。5. 实验报告踩坑记录四份报告里最容易丢分的五个细节5.1 截图不清、没有注释、总结太水实验报告的评分点其实很朴素格式、代码、结果、分析。但每年都有人在这四个点上翻车。我整理了四份报告里最常见的失分原因每条都按“现象→原因→解决”来写。现象一报告里的运行结果截图是一张黑乎乎的全屏终端图。原因截图时没有先清屏终端里残留了之前的命令记录输出结果被挤在中间导师根本看不清。解决清屏之后单独跑一次实验程序只截关键输出窗口如果输出太长剪掉中间部分保留头和尾并用红框标出关键行。现象二代码贴了上百行但一行注释都没有。原因觉得实验报告的代码就是“把源码粘贴过来”忽略了注释才是报告里体现理解程度的地方。解决核心函数和关键语句加中文注释注释不是解释语法而是说明“这一行在实验里起什么作用”。比如“sem_wait(empty)”的注释写“缓冲区有空位才继续否则阻塞”比写“等待信号量”好十倍。现象三实验总结写成了“通过本次实验我深刻认识到……”的流水账。原因不知道总结该写什么于是从网上抄了一段万能话术。解决总结要写三样东西——实验过程中遇到的最大的一个坑、你是怎么排查的、最后对操作系统哪个概念有了新的理解。写“这次实验让我真正理解了死锁的四个必要条件不是背出来的而是写代码时亲眼见到的”比任何空话都有说服力。现象四实验报告里出现了“胡乱的”“随便写写”等口语化词汇。原因把实验报告当成了自己的笔记或者从聊天记录里直接复制了一段话进来。解决交档之前全局搜索一遍“随便”“随便”“大概”“应该”统一改成描述性语言。现象五把别人报告里的实验环境直接抄成“Ubuntu 18.04”但自己机器实际是 macOS截图里却有明显差异。原因图省事觉得环境信息不重要。解决实验环境写自己机器上实际跑的版本。这份资源里的四份报告覆盖了进程管理、存储管理、设备管理和文件系统四个方向环境信息可以按自己的实际情况改但模板结构可以直接复用。5.2 避坑清单行距、封面、图表编号格式层面的坑同样致命。四份报告合集用的是标准实验报告模板包括封面信息、实验目的、实验内容、实验步骤、实验结果与分析、实验总结六个部分。在用的时候注意行距统一正文一般用 1.5 倍行距图表要有编号和标题图题在图下方表题在表上方代码用等宽字体和正文区分开对比度。还有一个容易忽略的点是时间。实验报告的提交日期、实验环境里的内核版本、编译器的版本这些信息如果写错了和代码运行时间对不上整份报告的真实性会打折扣。6. 把四份报告用成自己的东西模板迁移与二次验证拿到资源后不建议直接改个名字就交。比较稳妥的做法是拿其中任一份报告当模板先跑一遍代码再对照报告内容逐段确认结论和数据是否一致、代码和运行结果是否对得上、图表编号有没有断号。我一般会先把四份报告的目录结构列成清单确定哪一份和当前课程的实验要求最接近然后做三件事替换实验环境信息、重新生成本机的运行结果截图、重写实验总结段落。比如资源里进程管理那份报告用的代码是 C 写的 fork()如果你用的是 C或者你机器上是 Windows 加 WSL 环境那你需要先确认 fork() 能正常编译运行再截自己的运行结果。如果代码不能跑那份报告就纯粹变成了文字参考价值就浪费了。每份报告里的代码块我都建议至少编译运行一次哪怕只是验证输出和报告截图一致这个动作本身也能帮你发现一些细节比如不同环境下 PID 的数值范围差异。资源里四份报告之间是独立结构可以只取其中一份作为主线模板其余三份的实验小结和思考题部分用来补充你自己报告里的分析与总结段落。尤其当你的课程实验数量和内容不完全匹配时把其他实验的思考题答案改写成当前实验的“拓展讨论”比从零开始写更高效而且更贴近课程深度。从那以后我每次拿到参考报告都会强制自己先完整过一遍代码和运行环境再动笔改文档。这个习惯帮我避开了不少“报告写得很好但代码跑不起来”的尴尬。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑