C++进程调度模拟器:FCFS与SJF算法实战实现

发布时间:2026/10/28 14:23:59
C++进程调度模拟器:FCFS与SJF算法实战实现 简介本资源是一份面向计算机专业本科生的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.exeWindows可执行文件、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()。它们共享同一份进程数据vectorProcess processes但处理逻辑天差地别// FCFS完全按输入顺序排队 arrival_time 越小越靠前稳定排序 sort(processes.begin(), processes.end(), [](const Process a, const Process b) { return a.arrival_time b.arrival_time; }); // SJF先按到达时间分组再在“已到达”进程中挑服务时间最短的 // 关键不是全局排序是动态维护一个“就绪队列” priority_queueProcess, vectorProcess, 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 输出结果不只是数字而是带时间轴的调度过程快照程序运行后终端输出绝不是一串冷冰冰的平均值。它分三块FCFS详细过程列出每个进程的Start Time,Finish Time,Turnaround,Waiting并标注“当前时间推进到X进程Y开始执行”SJF详细过程同样格式但你会发现Start Time顺序和FCFS不同尤其当短作业晚到却早执行时对比汇总表用对齐的ASCII表格呈现Avg Turnaround,Avg Weighted Turnaround,Avg Waiting两算法并排差异一目了然。例如对input.txt中0 5 1 3 2 8 3 6 4 4FCFS平均等待时间可能是7.2而SJF压到4.0——这个差距不是理论推导是你亲眼看着进程在时间轴上“插队”产生的真实结果。这正是课程设计要你理解的调度算法不是数学公式是时间与资源的实时博弈。3. 编译、运行、调试绕过90%同学卡死的三大雷区包括那个“不是有效应用程序”的弹窗你以为解压双击pc_scheduling.exe就能跑现实是Windows 10/11家庭版默认不装VC运行库exe一启动就弹窗“指定的可执行文件不是此操作系统平台的有效应用程序”。这不是病毒警告是系统在说“我缺msvcp140.dll”。更糟的是有些同学用VS Code自己编译却卡在#include bits/stdc.h报错或g找不到-stdc11。下面这三条是我带过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?viewmsvc-170中文页面搜关键词即可。3.2 避坑VS Code里编译报#include bits/stdc.h错误 → 头文件路径没配对现象在VS Code里按CtrlShiftB编译报错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插件后按CtrlShiftP→ 输入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里按CtrlShiftP→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 vectorProcess 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(i1, 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所有进程同时到达T1T2...0进程到达时间服务时间P1010P201P302FCFS结果P1(0→10), P2(10→11), P3(11→13) → 平均等待 (01011)/3 7.0SJF结果P2(0→1), P3(1→3), P1(3→13) → 平均等待 (003)/3 1.0结论当到达时间相同时SJF优势最大化。这是教科书最爱举的例子但你要知道——它的前提“同时到达”在真实系统中极少发生。5.2 数据组2长作业早到短作业晚到FCFS的“饥饿”现场进程到达时间服务时间P10100P211P321FCFSP1(0→100), P2(100→101), P3(101→102) → P2等待99单位SJFP1(0→1), P2(1→2), P3(2→3) → P1被“插队”但P2/P3响应极快。关键洞察SJF缓解了短作业饥饿但牺牲了长作业的公平性。答辩时可以加一句“所以Linux的CFS调度器用虚拟运行时间平衡两者而不是纯SJF”。5.3 数据组3服务时间相同到达时间错开检验算法“无差别”场景进程到达时间服务时间P105P215P325FCFS SJF结果完全一致P1(0→5), P2(5→10), P3(10→15) → 平均等待 (048)/3 4.0为什么因为SJF选“最短”但所有服务时间都是5它退化为按到达时间排序——和FCFS一样。这证明SJF的优势只在服务时间差异大时才显现。如果你的实验数据里服务时间都接近那俩算法结果差不多不是代码错了是数据没选对。注意跑这三组时务必关闭抢占式开关SJF_PREEMPTIVE false因为非抢占式SJF才是课程要求的标准实现。抢占式是加分项不是基础分。从那以后我每次做调度算法实验都强制走一遍这三组数据验证——不是为了凑字数是怕自己被“平均值”骗了。真实系统的调度不是数学游戏是无数个“如果……会怎样”的组合爆炸。这个C源码的价值不在于它多完美而在于它给你一个可触摸、可修改、可证伪的沙盒。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询