ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

西南科技大学操作系统实验2:cpp2.cpp单文件解析与进程调度算法实现

西南科技大学操作系统实验2:cpp2.cpp单文件解析与进程调度算法实现 简介这份资源是西南科技大学计算机操作系统课程实验2的配套代码面向计算机科学与技术专业学生及正在学习操作系统原理的自学者用于通过编程实践加深对进程管理、内存管理、文件系统、设备管理、死锁预防与避免、线程与并发等核心知识的理解。压缩包内共1个文件为cpp源码整体约1KB体量轻便适合直接编译运行或作为实验参考模板。资源已有2061人学习下载说明其在课程实验场景中具有一定参考价值。读者可借助该代码对照实验要求梳理进程调度、同步互斥、系统调用等关键实现思路并在此基础上完成实验报告中的步骤分析与结果验证提升编程与调试能力为后续系统级开发打下基础。1. 从一份 cpp2.cpp 说起西南科技大学操作系统实验2到底练什么如果你手里正躺着一个计算机操作系统实验2.rar解压后只看到一个cpp2.cpp第一反应大概率是懵的——一个源文件能撑起一整个实验我当初拆这类课程包时也是这个反应。这份来自西南科技大学计算机操作系统课程的实验2走的是典型的“单文件多算法”路线把进程调度、内存置换、死锁避免这些核心机制塞进一个 C 文件里靠菜单驱动逐个跑给你看。它解决的不是“造一个操作系统”而是让你亲手把 FCFS、SJF、LRU、银行家算法这些纸面流程翻译成能跑出数字的代码。适合正在跟这门课、需要交实验报告的人也适合想拿一份能编译的骨架去改自己调度逻辑的从业者。下面我按“先看懂结构、再动手跑、最后避坑”的顺序拆。2. 拆开 cpp2.cpp单文件里藏了哪几套算法骨架2.1 先认清这份源码的组织方式拿到cpp2.cpp别急着编译先通读一遍结构。这类课程实验源码通常不会用工程化的多文件拆分而是把所有逻辑压在一个main里用while套switch做菜单。常见做法是定义几个struct表示进程控制块PCB或页面表项然后每个算法写成一个独立函数菜单里选编号调用。你要做的第一件事是找到这几个结构体定义它们决定了后面所有算法的数据长什么样。以进程调度为例PCB 里一般会有进程名、到达时间、服务时间、已运行时间、优先级、状态这几个字段。内存置换的页表项则会有页号、访问位、修改位、驻留标志。看懂字段含义后面调参数才不会瞎改。我一般会先在纸上把结构体字段抄一遍标上哪个是输入、哪个是算法运行时算出来的这样调试时一眼能看出是输入喂错了还是逻辑写错了。// 典型的 PCB 结构字段名可能不同按实际源码对照 struct PCB { char name[10]; // 进程名输入 int arriveTime; // 到达时间输入 int serviceTime; // 服务时间输入 int runTime; // 已运行时间算法运行时累加 int priority; // 优先级输入数值含义看算法约定 char state; // 状态W 等待 / R 运行 / F 完成 };这段结构体是整份源码的地基。arriveTime和serviceTime是你在菜单里手动输入或从预设数组读入的原始数据runTime和state是算法跑起来之后才会变的。很多人第一次跑结果不对不是算法写错而是把priority的数值方向搞反了——有的实现里数值越小优先级越高有的反过来这个必须回到源码里确认不能凭印象。2.2 进程调度算法的实现差异单文件里最占篇幅的通常是进程调度。FCFS 最好写按到达时间排个序依次执行就行SJF 要分“非抢占”和“抢占”两种非抢占是等当前进程跑完再挑最短的抢占是每来一个新进程就比较剩余时间优先级调度同理。多级反馈队列最复杂要维护多个就绪队列还要处理时间片用完后的降级。我建议的阅读顺序是先只看 FCFS 那个函数把它的输入输出跑通确认菜单能正确调用、结果能正确打印。然后再看 SJF对比它比 FCFS 多了哪几步排序或比较。这样一层层加比一上来啃多级反馈队列要稳。常见做法是每个算法函数都接收同一个 PCB 数组返回一个调度序列或直接打印甘特图式的执行顺序。你要留意的是周转时间和带权周转时间这两个指标怎么算的——周转时间 完成时间 - 到达时间带权周转时间 周转时间 / 服务时间这两个数在实验报告里是必须出现的。// FCFS 核心逻辑示意按到达时间排序后依次执行 void FCFS(PCB p[], int n) { sort(p, p n, [](PCB a, PCB b) { return a.arriveTime b.arriveTime; // 到达早的先执行 }); int currentTime 0; for (int i 0; i n; i) { if (currentTime p[i].arriveTime) currentTime p[i].arriveTime; // CPU 空闲等待 currentTime p[i].serviceTime; p[i].runTime p[i].serviceTime; p[i].state F; // 此处计算并打印周转时间、带权周转时间 } }这段代码的关键在currentTime的推进方式。如果当前时间小于下一个进程的到达时间说明 CPU 有空闲要先把时间跳到到达时间再执行。这个细节在 SJF 和优先级调度里同样存在漏掉就会导致周转时间算小。参数方面n是进程数量通常由菜单输入决定p[]是全局或主函数传入的数组。改数据时只改arriveTime和serviceTime别动runTime的初始值。2.3 内存置换与银行家算法的落点如果这份实验2还包含内存管理那cpp2.cpp里大概率有 LRU 或 FIFO 的页面置换模拟。LRU 的核心是记录每个页面最后一次被访问的时间缺页时淘汰时间最早的那个。实现上可以用一个访问计数数组每次访问就把对应页面的计数更新为当前时刻。FIFO 更简单用一个队列先进先出。银行家算法则是另一套逻辑维护可用资源向量、最大需求矩阵、已分配矩阵然后跑安全性检查找安全序列。这两块和进程调度的区别在于它们不涉及时间推进而是状态转移。调试时重点看缺页次数和安全序列是否唯一。银行家算法的安全序列可能不唯一只要找到一个就行但如果你一个都找不到而理论上有解那多半是Need矩阵算错了——Need Max - Allocation这个减法别搞反。3. 把 cpp2.cpp 跑起来编译、输入与结果验证3.1 编译环境与命令这类课程源码基本是标准 C不带图形库用 g 直接编译就行。Windows 上如果装了 MinGW 或者 Dev-C也能直接跑。我一般会在命令行里编译这样报错信息看得清楚。# Linux / macOS 下编译-o 指定输出文件名 g cpp2.cpp -o os_exp2 # 运行 ./os_exp2如果编译报错说找不到bits/stdc.h说明你用的不是 GCC 系编译器把它换成具体的头文件比如iostream、algorithm、cstring。如果报sort未定义检查有没有#include algorithm和using namespace std;。这些是课程源码最常见的两个编译坑跟算法本身无关。3.2 输入数据的组织方式跑起来之后菜单会问你选哪个算法然后让你输入进程数量和各进程参数。这里有个血泪经验输入顺序必须和源码里cin的顺序完全一致。有的源码是先读进程名再读到达时间再读服务时间有的把优先级插在中间。你输错一个后面全乱。我一般会先选一个算法随便输两组数据看打印出来的原始数据对不对确认输入解析没问题再正式跑实验数据。如果源码用的是预设数组而不是手动输入那就要找到那个数组定义直接改里面的数值。改完重新编译。这种方式更适合批量测试比如你想对比 FCFS 和 SJF 在同一组数据下的周转时间差异改一次数组跑两次就行。3.3 结果怎么验证才算对跑出结果别急着抄进报告先做两个检查。第一手工算一遍第一个进程的周转时间看和程序输出是否一致。第二看所有进程的完成时间是否单调递增如果出现后面的进程比前面的先完成那调度逻辑肯定有问题。对于银行家算法检查找到的安全序列里每个进程的Need是否都不超过当时的工作向量这是安全性的定义逐行核对一遍。常见做法是拿一组经典数据做回归测试比如三个进程、到达时间分别为 0、1、2服务时间为 5、3、2手工算出 FCFS 和 SJF 的结果然后跟程序输出对比。这组数据我用了很多次能同时暴露排序错误和时间推进错误。4. 避坑与排查这份实验源码最容易翻车的五个地方4.1 现象编译通过但运行直接闪退原因通常是数组越界。课程源码里经常用固定大小的数组比如PCB p[10]但菜单允许你输入大于 10 的进程数。或者字符串拷贝时用了strcpy但目标缓冲区不够长。解决方法是找到数组定义把大小改大或者在输入进程数后加一个范围检查。我一般会把p[10]改成p[100]一劳永逸。4.2 现象周转时间算出来是负数原因是currentTime没有正确处理 CPU 空闲。当第一个进程的到达时间大于 0 时如果直接currentTime serviceTime完成时间就会小于到达时间周转时间变成负数。解决方法是执行前先判断if (currentTime p[i].arriveTime) currentTime p[i].arriveTime;。这个判断在 FCFS、SJF、优先级调度里都要有漏一个就错一个。4.3 现象SJF 结果和手工算的不一样先确认你跑的是非抢占还是抢占版本。非抢占 SJF 只在当前进程完成后才重新选择抢占 SJF 每来一个新进程都要比较剩余时间。源码里如果只写了一种而实验要求另一种那结果对不上是正常的。解决方法是看实验指导书要求哪种然后改源码里的选择时机。另外SJF 比较的是服务时间还是剩余时间也要确认非抢占用服务时间抢占用剩余时间。4.4 现象LRU 缺页次数比 FIFO 还多这通常不是算法错而是访问序列的问题。LRU 在特定序列下确实可能比 FIFO 缺页多这叫 Belady 异常的反面情况。但如果你用的序列是随机的LRU 一般不会比 FIFO 差太多。先检查访问序列有没有输错再检查 LRU 的“最近使用”时间戳是不是每次访问都更新了。如果只在缺页时更新那就退化成了 FIFO。解决方法是确保每次访问命中时也更新时间戳。4.5 现象银行家算法找不到安全序列先检查Available向量有没有减去已经分配的资源。初始Available是系统总资源减去所有进程已分配资源之和如果直接拿总资源当Available那肯定能找到安全序列但那是错的。再检查Need矩阵是不是Max - Allocation。最后检查安全性检查的循环里工作向量Work有没有在进程完成后加上它的Allocation。这三步任何一步错安全序列都会找不到或者找到错的。5. 从能跑到能改把这份骨架变成你自己的调度实验把cpp2.cpp跑通只是及格线真正让这份资源值回票价的是改它。我一般会做三件事加一组随机数据生成、加一个结果对比、加一个指标输出。随机数据生成很简单用rand()造到达时间和服务时间跑一百组看哪个算法的平均周转时间更优。这比手工输几组数据有说服力得多。代码大概长这样// 生成 n 个进程的随机到达时间和服务时间 void genRandom(PCB p[], int n) { srand(time(0)); for (int i 0; i n; i) { p[i].arriveTime rand() % 10; // 到达时间 0-9 p[i].serviceTime rand() % 10 1; // 服务时间 1-10 p[i].runTime 0; p[i].state W; } }rand() % 10控制范围1避免服务时间为 0。跑对比时把同一组随机数据分别喂给 FCFS 和 SJF统计平均周转时间。你会发现 SJF 在大多数情况下更优但偶尔会因为长进程饥饿而出现极端值这正是实验报告里可以展开分析的点。第二个改动是加一个甘特图式的输出。不用图形库直接用字符打印执行顺序比如| P1 | P2 | P3 |每个进程下面标时间点。这样结果一目了然报告里也好看。实现上就是在调度循环里每执行一个进程就打印一次进程名和当前时间。第三个改动是给银行家算法加一个“请求资源”的交互。原始源码可能只做安全性检查你可以加一个功能输入某个进程的资源请求向量先判断Request Need且Request Available然后试探性分配再跑安全性检查安全就正式分配不安全就回滚。这个流程走一遍银行家算法的理解就到位了。最后说个习惯。我每次改完这类课程源码都会把原始文件备份成cpp2_orig.cpp改动的版本另存。因为课程实验经常要求交原始代码加修改说明备份能省很多事。另外实验报告里的结果截图最好在改之前和改之后各存一份对比着写分析比空谈理论有分量。希望帮到你。本文还有配套的精品资源点击获取
返回列表