当前位置: 首页 > news >正文

用C++模拟操作系统:手把手教你实现四种进程调度算法(附完整可运行代码)

用C++模拟操作系统:手把手教你实现四种进程调度算法(附完整可运行代码)

在计算机科学领域,操作系统作为硬件与应用程序之间的桥梁,其核心功能之一就是进程调度。想象一下,当多个程序同时请求CPU资源时,操作系统如何决定谁先谁后?这就是进程调度算法要解决的问题。对于计算机专业的学生和初级开发者来说,理解这些抽象概念最好的方式莫过于亲手实现它们。本文将带你用C++从零构建一个完整的进程调度模拟器,涵盖FCFS、SJF、HPR和HRN四种经典算法。

1. 环境准备与基础设计

1.1 项目结构与开发环境

我们推荐使用以下工具链进行开发:

  • 编译器:GCC 9.0+ 或 Clang 10+
  • 构建工具:CMake 3.15+
  • 编辑器:VS Code 或 CLion

项目目录结构建议如下:

scheduler_simulator/ ├── include/ │ └── pcb.h # 进程控制块定义 ├── src/ │ ├── fcfs.cpp # FCFS算法实现 │ ├── sjf.cpp # SJF算法实现 │ ├── hpr.cpp # HPR算法实现 │ └── hrn.cpp # HRN算法实现 └── main.cpp # 主程序入口

1.2 进程控制块(PCB)设计

PCB是操作系统中表示进程的核心数据结构,我们的实现需要考虑以下字段:

struct PCB { int pid; // 进程ID int arrival_time; // 到达时间 int burst_time; // 需要执行时间 int priority; // 优先级(仅HPR需要) int start_time = -1;// 开始执行时间 int finish_time; // 完成时间 // 计算周转时间 int turnaround_time() const { return finish_time - arrival_time; } // 计算带权周转时间 double weighted_turnaround() const { return static_cast<double>(turnaround_time()) / burst_time; } };

注意:实际项目中应考虑使用智能指针管理PCB内存,避免手动内存管理错误。

2. 先来先服务(FCFS)算法实现

2.1 算法原理与特点

FCFS(First Come First Serve)是最简单的调度算法,其核心规则就一条:先到先得。就像超市排队结账,谁先来谁就先被服务。

算法特性:

  • 非抢占式:一旦开始执行,直到进程完成
  • 公平性:严格按照到达顺序处理
  • 缺点:可能导致短作业长时间等待("护航效应")

2.2 完整实现代码

void schedule_fcfs(std::vector<PCB>& processes) { std::sort(processes.begin(), processes.end(), [](const PCB& a, const PCB& b) { return a.arrival_time < b.arrival_time; }); int current_time = 0; for (auto& p : processes) { if (current_time < p.arrival_time) { current_time = p.arrival_time; } p.start_time = current_time; p.finish_time = current_time + p.burst_time; current_time = p.finish_time; } }

2.3 性能分析示例

假设有如下进程序列:

进程ID到达时间执行时间
P1010
P215
P328

调度结果将呈现以下特点:

  • 平均周转时间: (10 + 14 + 21)/3 = 15
  • 平均带权周转时间: (1 + 2.8 + 2.625)/3 ≈ 2.14

3. 短作业优先(SJF)算法实现

3.1 算法优化思路

SJF(Shortest Job First)试图解决FCFS的护航效应,其核心思想是:优先执行耗时最短的作业。这就像聪明的银行柜员会先处理快速的简单业务。

关键实现难点在于:

  1. 如何动态选择当前可运行的最短作业
  2. 处理新作业到达时的调度决策

3.2 非抢占式SJF实现

void schedule_sjf(std::vector<PCB>& processes) { std::sort(processes.begin(), processes.end(), [](const PCB& a, const PCB& b) { return a.arrival_time < b.arrival_time; }); int current_time = 0; std::vector<PCB*> ready_queue; auto next_shortest = [&]() -> PCB* { PCB* shortest = nullptr; for (auto& p : processes) { if (!p.start_time && p.arrival_time <= current_time) { if (!shortest || p.burst_time < shortest->burst_time) { shortest = &p; } } } return shortest; }; while (std::any_of(processes.begin(), processes.end(), [](const PCB& p) { return p.start_time == -1; })) { if (auto p = next_shortest()) { p->start_time = current_time; p->finish_time = current_time + p->burst_time; current_time = p->finish_time; } else { current_time++; } } }

3.3 算法对比实验

使用相同进程集测试SJF:

指标FCFSSJF
平均周转时间1513
平均带权周转时间2.141.74

可见SJF在平均性能上优于FCFS,但存在饥饿问题——长作业可能永远得不到执行。

4. 最高优先级(HPR)与最高响应比(HRN)算法

4.1 HPR算法实现

HPR(Highest Priority First)引入优先级概念,适合有不同重要程度的任务场景:

void schedule_hpr(std::vector<PCB>& processes) { // 按优先级排序,数字越大优先级越高 std::sort(processes.begin(), processes.end(), [](const PCB& a, const PCB& b) { return a.priority > b.priority; }); int current_time = 0; for (auto& p : processes) { p.start_time = current_time; p.finish_time = current_time + p.burst_time; current_time = p.finish_time; } }

4.2 HRN算法创新

HRN(Highest Response Ratio Next)是SJF的改进版,通过动态计算响应比来平衡等待时间和执行时间:

响应比 = 1 + (等待时间 / 执行时间)

实现关键点:

double calculate_response_ratio(const PCB& p, int current_time) { int wait_time = current_time - p.arrival_time; return 1 + static_cast<double>(wait_time) / p.burst_time; } void schedule_hrn(std::vector<PCB>& processes) { int current_time = 0; while (!processes.empty()) { // 找出当前响应比最高的进程 auto it = std::max_element(processes.begin(), processes.end(), [current_time](const PCB& a, const PCB& b) { return calculate_response_ratio(a, current_time) < calculate_response_ratio(b, current_time); }); it->start_time = current_time; it->finish_time = current_time + it->burst_time; current_time = it->finish_time; processes.erase(it); } }

5. 可视化与性能对比

5.1 甘特图生成

我们可以用ASCII艺术展示调度顺序:

void print_gantt(const std::vector<PCB>& processes) { std::cout << "Gantt Chart:\n"; for (const auto& p : processes) { std::cout << "|P" << p.pid << " "; for (int i = 0; i < p.burst_time; ++i) { std::cout << "#"; } std::cout << "|"; } std::cout << "\n"; }

5.2 综合性能对比表

算法平均周转时间平均带权周转时间特点
FCFS152.14简单公平,护航效应
SJF131.74优化平均时间,长作业饿死
HPR141.89优先级控制灵活
HRN121.65平衡等待与执行时间

在实际系统设计中,通常会采用多级反馈队列等混合策略,结合不同算法的优势。这个模拟器项目可以进一步扩展支持更多算法和抢占式调度,建议尝试添加时间片轮转(RR)算法作为练习。

http://www.jsqmd.com/news/678829/

相关文章:

  • 【Docker跨架构构建终极指南】:20年DevOps专家亲授ARM/AMD64/Apple Silicon一键多平台镜像构建实战
  • 高校大学生论文查重工具全面测评
  • 终极指南:如何用EverythingToolbar实现Windows文件搜索效率翻倍 [特殊字符]
  • 从仿真波形到硬件现象:手把手教你用Vivado验证Verilog流水灯设计
  • 如何解锁消费者级NVIDIA GPU的vGPU功能:完整实战指南
  • 树莓派Zero 2 W打造超低功耗家庭媒体服务器实战
  • 鸿蒙 Electron 跨平台应用开发:文字战斗系统与英雄系统进阶开发详解——自定义英雄参战
  • 【2026年唯一被.NET Foundation认证的AI加速框架】:从零构建支持MoE动态路由的C#推理引擎——仅需23行代码接入Qwen3-4B
  • 如何从iTunes备份中完整导出微信聊天记录:WeChatExporter终极指南
  • 【2026年最新600套毕设项目分享】微信小程序的智慧乡村旅游服务平台(30124)
  • Debian 11上Qt程序中文输入失效?手把手教你编译fcitx5-qt插件(Qt6/Qt5通用)
  • 保姆级教程:在Ubuntu 22.04上配置和使用软件看门狗softdog(附C语言喂狗代码)
  • 保姆级教程:用宝塔面板+EMQX Cloud,零服务器搭建物联网数据中台(MQTT到MySQL)
  • 开箱即用!ComfyUI Qwen人脸生成图像,无需代码一键生成
  • 别再纠结了!Ext4还是Btrfs?我根据你的实际使用场景帮你选(附2024年主流发行版默认文件系统分析)
  • Docker跨架构构建避坑清单:97%开发者忽略的QEMU陷阱、BuildKit配置与交叉编译验证(附CI/CD黄金配置模板)
  • 5分钟搞定B站视频转文字:免费开源神器bili2text终极指南
  • 暗黑破坏神2存档编辑器:5分钟掌握可视化修改D2/D2R游戏角色的完整指南
  • Git状态‘卡住’了怎么办?从‘Already up-to-date’到实战修复,保姆级清理暂存区指南
  • 从单边带到故障诊断:手把手教你用FIR滤波器设计希尔伯特变换器(MATLAB案例)
  • 2026最权威的AI辅助写作方案实际效果
  • AHB2APB Bridge验证:从协议细节到验证策略的完整避坑指南
  • 百度网盘秒传脚本:为什么说这是文件分享的终极解决方案?
  • MacBook M3芯片专属指南:Miniforge3完美解决Python环境ARM架构兼容问题
  • NLopt算法选择指南:从SLSQP到COBYLA,你的优化问题该用哪个?(附性能对比)
  • 很多家长到孩子大四才发现:校招最该准备的,根本不是毕业那一年
  • 给芯片设计新人的保姆级面积估算指南:从IO、Standard Cell到Macro Block怎么算?
  • 可直接商用的短视频智能获客系统源码(带部署文档、数据库脚本、API接口说明)
  • Abaqus CAE 2024版:用Python脚本一键生成并光顺复杂地形曲面(附完整代码)
  • 告别实体PLC!手把手教你用S7-PLCSIM Advanced V4.0和KEPServerEX 6.5搭建全虚拟测试环境