☰
C++进程调度模拟器:FCFS与SJF算法实战实现
2026/10/28 14:23:41 网站建设 项目流程

简介:本资源是一份面向计算机专业本科生的C++课程设计大作业,聚焦操作系统核心知识点——进程调度算法的编程实现与性能对比分析。通过完整模拟FCFS(先来先服务)和SJF(短作业优先)两种经典调度策略,帮助学习者深入理解进程到达时间、服务时间、完成时间、周转时间、带权周转时间及等待时间等关键指标的计算逻辑与算法差异。压缩包共3个文件(1个核心cpp源码、1个README.md说明文档、1个可直接运行的exe程序),总大小仅36KB,结构精简、开箱即用,便于调试验证与课堂演示。目前已有2852人学习下载,代码逻辑清晰、注释完备,附带输入样例与结果输出格式说明,特别适合课程设计答辩准备、期末大作业参考及操作系统实验课拓展实践。

1. 这不是玩具代码:一个能跑通、能改参数、能交作业的C++进程调度模拟器,专治“FCFS/SJF手算到崩溃”和“VS编译报错找不到msvcp140.dll”

你是不是刚打开操作系统课设题干,看到“模拟FCFS和SJF调度,计算周转时间、带权周转时间、平均等待时间……”就头皮发紧?手算5个进程还能扛,但老师突然说“把n改成20,再加一组到达时间乱序的数据”,瞬间想关电脑?更别提用C++写完一编译——弹窗:“程序‘pc_scheduling.exe’无法运行:指定的可执行文件不是此操作系统平台的有效应用程序”。这根本不是你的代码问题,是缺了那个藏在角落里的Microsoft Visual C++ 2015-2022 Redistributable (x64)。这个.zip包里塞进来的不是PPT截图或半截伪代码,而是一个开箱即用、带完整.cpp源码、可执行.exe、带README.md说明、连输入格式都给你刻进注释里的实操工程。它不讲抽象调度理论,只做三件事:① 读入你手写的进程数据(到达时间+服务时间);② 同时跑FCFS和SJF两套逻辑,输出每一步谁在CPU上、谁在等、谁刚结束;③ 算出所有要求的指标,表格对齐,小数点后两位,直接复制进实验报告。适合大二操作系统课设、期末大作业、或者想快速验证调度算法差异的实操派——别再用Excel手算了,让C++替你算,你只管看结果、调参数、写分析。

2. 从解压到双击运行:5分钟走通全流程,看清FCFS与SJF的本质差异在哪一行代码里

这个资源包结构极简,但每一层都直指实操痛点:pc_scheduling-master/是根目录,里面只有4个东西——pc_scheduling.cpp(核心源码)、pc_scheduling.exe(Windows可执行文件)、README.md(人话说明)、还有一个空着的input.txt(你填数据的地方)。没有CMakeLists.txt,没有build文件夹,没有让你配环境变量的玄学步骤。它默认站在“学生交作业最后一刻”的立场设计:能双击就跑,能改就改,能交就交。下面带你从解压开始,一帧一帧拆解它怎么工作,重点不是“它写了什么”,而是“你改哪一行就能控制它怎么算”。

2.1 输入数据:用纯文本定义你的实验场景,格式错一个空格就全崩

所有调度逻辑的起点,是你自己写的input.txt。它不是JSON也不是XML,就是最朴素的纯文本,格式固定为两行:

5 0 5 1 3 2 8 3 6 4 4

第一行是进程总数n(这里是5);第二行是2*n个整数,严格按“到达时间、服务时间”交替排列:T1 S1 T2 S2 ... Tn Sn。上面例子表示:

  • 进程1:时刻0到达,需服务5单位时间
  • 进程2:时刻1到达,需服务3单位时间
  • 进程3:时刻2到达,需服务8单位时间
  • 进程4:时刻3到达,需服务6单位时间
  • 进程5:时刻4到达,需服务4单位时间

提示:这个顺序就是FCFS的天然队列顺序。但SJF会打乱它——关键就在这里。你改input.txt,就是在定义自己的实验场景。比如想测试“SJF是否真比FCFS快”,就把服务时间拉得更悬殊:0 10 1 1 2 1 3 1 4 1,这时FCFS会让长作业卡住所有短作业,而SJF会立刻切过去跑那堆1单位的活儿。

2.2 核心逻辑:pc_scheduling.cpp里藏着两个调度器的“心跳节拍”

打开pc_scheduling.cpp,别被200多行吓到。真正驱动调度的,是两个并列的函数:fcfs_schedule()和sjf_schedule()。它们共享同一份进程数据(vector<Process> processes),但处理逻辑天差地别:

// FCFS:完全按输入顺序排队, arrival_time 越小越靠前(稳定排序) sort(processes.begin(), processes.end(), [](const Process& a, const Process& b) { return a.arrival_time < b.arrival_time; }); // SJF:先按到达时间分组,再在“已到达”进程中挑服务时间最短的 // 关键:不是全局排序!是动态维护一个“就绪队列” priority_queue<Process, vector<Process>, CompareByBurst> ready_queue;

看懂这两段,你就抓住了本质:FCFS是静态排序,SJF是动态选择。FCFS的sort一行搞定,后续就是线性遍历;SJF却要模拟真实CPU的“抢占感”——时间推进到某时刻,把所有arrival_time <= current_time的进程塞进ready_queue,然后ready_queue.top()永远吐出当前最短的那个。CompareByBurst这个仿函数,就是SJF的“灵魂判据”,它让priority_queue按burst_time升序排列(小根堆)。如果你把return a.burst_time > b.burst_time;改成<,整个SJF就反过来了——这是你调试时最该盯的参数。

2.3 输出结果:不只是数字,而是带时间轴的调度过程快照

程序运行后,终端输出绝不是一串冷冰冰的平均值。它分三块:

  1. FCFS详细过程:列出每个进程的Start Time,Finish Time,Turnaround,Waiting,并标注“当前时间推进到X,进程Y开始执行”;
  2. SJF详细过程:同样格式,但你会发现Start Time顺序和FCFS不同,尤其当短作业晚到却早执行时;
  3. 对比汇总表:用对齐的ASCII表格呈现Avg Turnaround,Avg Weighted Turnaround,Avg Waiting,两算法并排,差异一目了然。

例如,对input.txt中0 5 1 3 2 8 3 6 4 4,FCFS平均等待时间可能是7.2,而SJF压到4.0——这个差距不是理论推导,是你亲眼看着进程在时间轴上“插队”产生的真实结果。这正是课程设计要你理解的:调度算法不是数学公式,是时间与资源的实时博弈。

3. 编译、运行、调试:绕过90%同学卡死的三大雷区,包括那个“不是有效应用程序”的弹窗

你以为解压双击pc_scheduling.exe就能跑?现实是,Windows 10/11家庭版默认不装VC++运行库,exe一启动就弹窗:“指定的可执行文件不是此操作系统平台的有效应用程序”。这不是病毒警告,是系统在说:“我缺msvcp140.dll”。更糟的是,有些同学用VS Code自己编译,却卡在#include <bits/stdc++.h>报错,或g++找不到-std=c++11。下面这三条,是我带过3届操作系统课设、帮67个同学修好环境后总结的血泪避坑清单,按发生概率从高到低排:

3.1 避坑:双击exe报“不是有效应用程序” → 缺VC++运行库,不是你的错

  • 现象:双击pc_scheduling.exe,弹窗报错,任务管理器里看不到进程。
  • 原因:pc_scheduling.exe是用Visual Studio 2019/2022编译的,依赖Microsoft Visual C++ 2015-2022 Redistributable (x64)。Win10家庭版默认只装了x86版,而这个exe是x64的。
  • 解决:去微软官网搜“Microsoft Visual C++ 2015-2022 Redistributable (x64)”,下最新版(如vc_redist.x64.exe),以管理员身份运行安装。装完重启,再双击exe,秒跑通。别信第三方下载站,微软官网链接是:https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170(中文页面搜关键词即可)。

3.2 避坑:VS Code里编译报#include <bits/stdc++.h>错误 → 头文件路径没配对

  • 现象:在VS Code里按Ctrl+Shift+B编译,报错fatal error: bits/stdc++.h: No such file or directory。
  • 原因:<bits/stdc++.h>是GCC的扩展头文件,MSVC(微软编译器)根本不认。原作者用的是MinGW-w64或Code::Blocks,你却用VS自带的MSVC编译器。
  • 解决:换编译器,别硬刚。在VS Code里装C/C++插件后,按Ctrl+Shift+P→ 输入C/C++: Edit Configurations (UI)→ 在Compiler path里选g++.exe(来自MinGW-w64),而不是cl.exe。或者更简单:直接用Code::Blocks(官网免费)打开.cpp,它默认配好MinGW,一键编译。

3.3 避坑:输入数据格式错位导致结果全乱 → 空格和换行是隐形杀手

  • 现象:input.txt里明明写了5和0 5 1 3...,但程序输出Process 1: Turnaround = -1,或直接崩溃。
  • 原因:input.txt第二行末尾多了空格,或用了中文全角空格;又或者第一行5后面跟了不可见字符(如Windows记事本保存的BOM头)。
  • 解决:用VS Code或Notepad++打开input.txt,开启“显示所有字符”(VS Code里按Ctrl+Shift+P→Toggle Render Whitespace)。确认:第一行只有5和回车;第二行是纯数字+英文空格,结尾无空格,无tab,无BOM。终极保险:用printf在代码里加一句cout << "Read n=" << n << endl;,看它读到的n是不是你写的数字。

4. 深度定制:改三处代码,让这个课设源码变成你的原创作品,轻松应对答辩提问

交作业不是终点,答辩才是生死局。老师最爱问:“如果我想加一个优先级调度(Priority Scheduling),怎么改?” 或者 “SJF非抢占式和抢占式区别在哪?你这个实现是哪种?” 如果你只会说“我抄的”,当场凉透。但如果你能指着代码说:“您看,这里sjf_schedule()函数里,我只要把while (!ready_queue.empty())循环里的current_time += p.burst_time;改成current_time++,再加个if (p.burst_time > 0) { p.burst_time--; },就是抢占式SJF了”,老师眼睛会亮。下面这三处修改,成本最低、效果最炸,改完就是你的原创逻辑:

4.1 加一个“抢占式SJF”开关:用布尔变量控制调度粒度

原sjf_schedule()是非抢占式:一旦进程开始执行,就跑完它的全部burst_time。要变抢占式,核心是把“时间单位”从“服务时间”切成“1单位时间片”。在pc_scheduling.cpp顶部加一个全局开关:

// 在 #include 下方,全局变量区添加 bool SJF_PREEMPTIVE = false; // 默认非抢占,设true则变抢占式

然后在sjf_schedule()函数里,找到主循环:

// 原非抢占式:直接加总服务时间 current_time += p.burst_time; // 改成抢占式:每次只推进1单位,动态重排就绪队列 if (SJF_PREEMPTIVE) { p.burst_time--; // 执行1单位 current_time++; // 时间推进1单位 if (p.burst_time > 0) { // 还没跑完,放回就绪队列(注意:此时可能有新进程到达) ready_queue.push(p); } else { // 跑完了,记录完成时间 p.finish_time = current_time; results.push_back(p); } } else { // 原逻辑保持不变 current_time += p.burst_time; p.finish_time = current_time; results.push_back(p); }

改完重新编译,SJF_PREEMPTIVE = true时,你会看到进程像真实CPU一样“切片”执行,短作业插入长作业中间——这就是答辩时你能画在白板上的调度甘特图。

4.2 输出甘特图:用ASCII字符画出CPU时间轴,让老师一眼看懂

光有数字不够直观。在main()函数末尾,加一个print_gantt_chart()函数,用|和-画时间轴:

void print_gantt_chart(const vector<Process>& results, const string& algo_name) { cout << "\n=== " << algo_name << " Gantt Chart ===\n"; cout << "Time: "; for (int t = 0; t <= results.back().finish_time; t++) { cout << setw(2) << t << " "; } cout << "\nProc: "; for (int t = 0; t <= results.back().finish_time; t++) { char proc_id = ' '; for (const auto& p : results) { if (t >= p.start_time && t < p.finish_time) { proc_id = 'A' + (p.id - 1); // 进程1→A, 2→B... break; } } cout << setw(2) << proc_id << " "; } cout << "\n"; }

调用它:print_gantt_chart(fcfs_results, "FCFS");和print_gantt_chart(sjf_results, "SJF");。运行后,终端会打出类似这样的图:

=== FCFS Gantt Chart === Time: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Proc: A A A A A B B B C C C C C C C C D D D D

老师一看就懂:A跑了5单位,B接着跑3单位……这比讲十分钟理论管用。

4.3 支持多种输入方式:从文件读取升级为命令行参数,秀出工程素养

现在只能读input.txt,太死板。加一个命令行参数解析,让pc_scheduling.exe 5 0 5 1 3 2 8直接运行:

// 在 main() 开头,替换原来的 ifstream 读取 if (argc > 2) { // 命令行参数:./exe n t1 s1 t2 s2 ... n = stoi(argv[1]); for (int i = 0; i < n; i++) { int t = stoi(argv[2 + 2*i]); int s = stoi(argv[2 + 2*i + 1]); processes.push_back(Process(i+1, t, s)); } } else { // 原文件读取逻辑 ifstream fin("input.txt"); // ... 原有代码 }

这样,你在命令行敲pc_scheduling.exe 3 0 10 1 1 2 1,程序立刻用这组数据跑,不用反复改input.txt。答辩时演示“不同数据集对比”,就显得特别老练。

5. 验证与对比:用三组典型数据跑出调度算法的“性格画像”,避开教科书陷阱

很多同学交报告时只跑老师给的例题,结果答辩被问:“如果所有进程同时到达,FCFS和SJF结果一样吗?” 或者 “SJF一定比FCFS平均等待时间短吗?” —— 这些问题,恰恰暴露了你没真正理解算法边界。我建议你用以下三组精心设计的数据,跑一遍,把结果截图贴进报告,结论比抄教材深刻十倍:

5.1 数据组1:所有进程同时到达(T1=T2=...=0)

进程到达时间服务时间
P1010
P201
P302
  • FCFS结果:P1(0→10), P2(10→11), P3(11→13) → 平均等待 =(0+10+11)/3 = 7.0
  • SJF结果:P2(0→1), P3(1→3), P1(3→13) → 平均等待 =(0+0+3)/3 = 1.0
  • 结论:当到达时间相同时,SJF优势最大化。这是教科书最爱举的例子,但你要知道——它的前提“同时到达”在真实系统中极少发生。

5.2 数据组2:长作业早到,短作业晚到(FCFS的“饥饿”现场)

进程到达时间服务时间
P10100
P211
P321
  • FCFS:P1(0→100), P2(100→101), P3(101→102) → P2等待99单位!
  • SJF:P1(0→1), P2(1→2), P3(2→3) → P1被“插队”,但P2/P3响应极快。
  • 关键洞察:SJF缓解了短作业饥饿,但牺牲了长作业的公平性。答辩时可以加一句:“所以Linux的CFS调度器用虚拟运行时间平衡两者,而不是纯SJF”。

5.3 数据组3:服务时间相同,到达时间错开(检验算法“无差别”场景)

进程到达时间服务时间
P105
P215
P325
  • FCFS & SJF结果完全一致:P1(0→5), P2(5→10), P3(10→15) → 平均等待 =(0+4+8)/3 = 4.0
  • 为什么?因为SJF选“最短”,但所有服务时间都是5,它退化为按到达时间排序——和FCFS一样。这证明:SJF的优势只在服务时间差异大时才显现。如果你的实验数据里服务时间都接近,那俩算法结果差不多,不是代码错了,是数据没选对。

注意:跑这三组时,务必关闭抢占式开关(SJF_PREEMPTIVE = false),因为非抢占式SJF才是课程要求的标准实现。抢占式是加分项,不是基础分。

从那以后我每次做调度算法实验,都强制走一遍这三组数据验证——不是为了凑字数,是怕自己被“平均值”骗了。真实系统的调度不是数学游戏,是无数个“如果……会怎样”的组合爆炸。这个C++源码的价值,不在于它多完美,而在于它给你一个可触摸、可修改、可证伪的沙盒。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询