操作系统实验1—实现单处理机下的进程调度程序

文章目录

  • 操作系统实验1—实现单处理机下的进程调度程序
    • 实验描述
    • 设计思路
    • 上机代码
    • 测试结果
    • 心得体会

实验描述

实验内容:

编写一个单处理机下的进程调度程序,模拟操作系统对进程的调度。

实验目的:

进程是操作系统中最基本、最重要的概念,进程调度又是操作系统的核心模块。本实验要求学生独立设计并实现进程调度模拟程序,以加深对进程控制块概念和各种进程调度算法的理解。

实验要求:

  1. 可以随机输入若干进程,支持先来先服务、短作业优先、最短剩余时间优先、时间片轮转、动态优先级调度算法,能够输出进程的调度过程。具体信息见测试用例格式说明。
  2. 每个进程由一个进程控制块表示。
  3. 实现先来先服务调度算法:进程到达时间可由进程创建时间表示。进程到达时间相同时,优先处理进程号小的进程。
  4. 实现短作业优先调度算法:可指定进程要求的运行时间。进程运行时间相同时,按照先来先服务原则进行处理。
  5. 实现最短剩余时间优先调度算法:可指定进程要求的运行时间。进程运行时间相同时,按照先来先服务原则进行处理。
  6. 实现时间片轮转调度算法:可指定生成时间片大小。进程到达时间相同时,优先处理进程号小的进程;进程执行完一个时间片进入就绪队列时,其优先级低于首次进入就绪队列的进程。
  7. 实现动态优先级调度算法:可指定进程的初始优先级(优先级与优先数成反比,优先级最高为0),优先级改变遵循下列原则:进程在就绪队列中每停留一个时间片(停留时间>0),优先级加1,进程每运行一个时间片,优先级减3。进程到达时间相同时,优先处理进程号小的进程,且仅在时间片完或进程运行结束时发生进程调度。

测试用例格式如下:

输入:
调度算法
进程号/到达时间/运行时间/优先级/时间片

其中调度算法选项为:
1----先来先服务,
2----短作业优先,
3----最短剩余时间优先,
4----时间片轮转,
5----动态优先级

输出:
调度顺序/进程号/开始运行时间/结束运行时间/优先级

测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 1
1/0/24/1/1
2/0/3/1/1
3/0/3/1/1
1/1/0/24/1
2/2/24/27/1
3/3/27/30/1
1秒 64M 0
测试用例 2 2
1/0/7/1/1
2/2/4/1/1
3/4/1/1/1
4/5/4/1/1
1/1/0/7/1
2/3/7/8/1
3/2/8/12/1
4/4/12/16/1
1秒 64M 0
测试用例 3 3
1/0/7/1/1
2/2/4/1/1
3/4/1/1/1
4/5/4/1/1
1/1/0/2/1
2/2/2/4/1
3/3/4/5/1
4/2/5/7/1
5/4/7/11/1
6/1/11/16/1
1秒 64M 0
测试用例 4 4
1/0/53/1/20
2/0/17/1/20
3/0/68/1/20
4/0/24/1/20
1/1/0/20/1
2/2/20/37/1
3/3/37/57/1
4/4/57/77/1
5/1/77/97/1
6/3/97/117/1
7/4/117/121/1
8/1/121/134/1
9/3/134/154/1
10/3/154/162/1
1秒 64M 0
测试用例 5 5
1/0/3/1/2
2/0/4/1/2
3/0/2/3/2
4/2/1/1/2
5/2/4/4/2
1/1/0/2/4
2/2/2/4/3
3/4/4/5/3
4/3/5/7/3
5/1/7/8/4
6/2/8/10/3
7/5/10/12/3
8/5/12/14/6
1秒 64M 0

设计思路

因为每一个进程输入的时候需要输入进程号、到达时间、运行时间、优先级、时间片五个属性,想到使用结构体来存储这些属性;同时进程输出的时候又要有调度顺序、开始运行时间、结束运行时间三个属性,以及短作业优先算法中还要判断进程是否运行结束,所以将进程需要用到的全部属性都存储在结构体里面。

时间片轮转算法中需要用到队列+结构体数组的形式来实现算法,其余四个算法使用结构体数组的形式实现算法。

struct process
{int pid;       //进程号int comeTime;  //到达时间int runTime;  //运行所需时间int beginTime;  //开始运行的时间int endTime;   //结束运行的时间int order;     //调度顺序int priority; //优先级int slot;      //时间片int finish;        //结束标志
}que[1010];queue<process>q;   //就绪队列,用于时间片轮转算法

程序概要设计如下图所示:

  1. main()函数是主程序的入口,接受程序输入,并按照输入的调度信号选择相应的算法模块进行运行。
  2. FCFS()函数是先来先服务算法,按照到来时间/进程号排序,先来到的进程首先处理,并将处理结果输出。
  3. SJF()函数是非剥夺的短作业优先算法,按照到来时间/运行时间/进程号排序,每次找出运行时间最短的进程运行,注意要按断进程是否已经运行结束,最后将结果输出。
  4. SRTF()函数是剥夺式的短作业优先算法,按照到来时间/运行时间/进程号排序,每次找出运行时间最短的进程运行,同时剥夺掉当前在运行的进程,注意要按断进程是否已经运行结束,最后将结果输出。
  5. RR()函数是时间片轮转算法,按照到来时间/进程号排序,每个进程运行一个时间片时间,注意判断进程是否运行结束,并将处理结果输出。
  6. DPSA()是动态优先级调度算法,按照到来时间/进程号排序,每个进程根据优先级分配运行时间,同时要动态调整进程的优先级,注意判断进程是否运行结束,并将处理结果输出。
  7. cmp1()是排序函数 1,按照到来时间/进程号排序。
  8. cmp2()是排序函数 2,按照到来时间/运行时间/进程号排序。
int main();      //主程序入口
void FCFS();    //先来先服务算法
void SJF();     //不可剥夺的短作业优先算法
void SRTF();    //可剥夺式的短作业优先算法
void RR();      //时间片轮转算法
void DPSA();    //动态优先级算法
bool cmp1(process, process);//排序函数1,用于FCFS、RR、DPSA
bool cmp2(process, process);//排序函数 2,用于 SJF、SRTF

上机代码

代码使用 C++ 语言进行编写

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
struct process
{int pid;//进程号 int comeTime;//到达时间 int runTime;//运行所需时间 int beginTime;//开始运行的时间 int endTime;//结束运行的时间 int order;//调度顺序 int priority;//优先级 int slot;//时间片 int finish;//结束标志
}que[1010];
void FCFS();//先来先服务
void SJF();//不可剥夺的短作业优先算法
void SRTF();//可剥夺式的短作业优先算法
void RR();//时间片轮转
void DPSA();//动态优先级
bool cmp1(process, process);//FCFS、RR、DPSA
bool cmp2(process, process);//SJF、SRTF
int num;//输入的总进程数
const int IsEnd = 1;//进程已经结束
const int NoEnd = 0;//进程还未结束
int main()
{//freopen("osin.txt", "r", stdin); //freopen("osout.txt", "w", stdout); int sig = 0;cin >> sig;   //算法选择标志 //读入数据 num = 0;while (~scanf("%d/%d/%d/%d/%d", &que[num].pid, &que[num].comeTime, &que[num].runTime, &que[num].priority, &que[num].slot)){que[num].beginTime = que[num].endTime = que[num].order = 0;que[num].finish = NoEnd;num++;}//选择算法 switch (sig){case 1:FCFS(); break;case 2:SJF(); break;case 3:SRTF(); break;case 4:RR(); break;case 5:DPSA(); break;}return 0;
}
void FCFS()
{sort(que, que + num, cmp1);//先来后到排好序 for (int i = 0; i < num; i++){que[i].order = i + 1;if (i == 0)//第一个进程特判一下 {que[i].beginTime = que[i].comeTime;}else{que[i].beginTime = max(que[i].comeTime, que[i - 1].endTime);}que[i].endTime = que[i].beginTime + que[i].runTime;//输出 printf("%d/%d/%d/%d/%d\n", que[i].order, que[i].pid, que[i].beginTime, que[i].endTime, que[i].priority);}
}
void SJF()
{sort(que, que + num, cmp2);int lastTime = que[0].comeTime;//当前时间 int tmp = 0;//每次选中的短作业 for (int i = 0; i < num; i++)//筛选num次,每次选出最佳的短作业 {bool isBool = false;//判断当前时间是否有短作业在就绪队列中 while (1){if (i == 0){//排序后的第一个肯定满足条件,特判 break;}else{for (int j = 1; j < num; j++)//for一遍的复杂度为O(n),比排序O(nlogn)快 {if (que[j].finish == IsEnd)//当前短作业已经结束就跳过 continue;if (que[j].comeTime <= lastTime)//当前短作业在就绪队列中 {if (isBool == false)//没有标记最优短作业 {isBool = true;tmp = j;}else//已经标记了最优短作业 {//比较,更新最优短作业 //当短作业运行时间相等时,优先调度进程号小的短作业执行 if (que[j].runTime < que[tmp].runTime)tmp = j;else if (que[j].runTime == que[tmp].runTime&&que[j].pid < que[tmp].pid)tmp = j;}}}if (isBool)//如果存在短进程满足条件就输出 break;else//不存在就把时间后移再寻找 lastTime++;}}que[tmp].order = i + 1;que[tmp].beginTime = max(que[tmp].beginTime, lastTime);que[tmp].endTime = que[tmp].beginTime + que[tmp].runTime;printf("%d/%d/%d/%d/%d\n", que[tmp].order, que[tmp].pid, que[tmp].beginTime, que[tmp].endTime, que[tmp].priority);lastTime = que[tmp].endTime;//更新当前时间 que[tmp].finish = IsEnd;//标记短作业结束 }
}
void SRTF()
{sort(que, que + num, cmp2);int lastTime = que[0].comeTime;int ID = 1;//输出顺序 int tmp = 0, counts = 0;//当前进程,输出次数 int isRun = -1, start = 0;//当前是否有进程运行,运行开始时间 while (counts < num){while (que[tmp].comeTime <= lastTime && tmp < num)//当前时间内的进程 {tmp++;}int minx = 0x3f3f3f, minId = -1;//最短时间和下标 for (int i = 0; i < tmp; i++)//寻找当前进程中剩余运行时间最短的进程 {if (que[i].runTime < minx && que[i].finish == NoEnd){minx = que[i].runTime;minId = i;}}if (minId == -1)//如果当前时间进程都结束了就等待下一个进程 {lastTime = que[tmp].comeTime;continue;}if (isRun == -1)//当前没有进程在运行 {isRun = minId;start = max(que[isRun].comeTime, lastTime);//运行刚找到的进程 }//如果找到进程的剩余运行时间小于当前进程的剩余运行时间 if (que[minId].runTime < que[isRun].runTime){que[isRun].order = ID++;que[isRun].beginTime = start;que[isRun].endTime = lastTime;printf("%d/%d/%d/%d/%d\n", que[isRun].order, que[isRun].pid, que[isRun].beginTime, que[isRun].endTime, que[isRun].priority);isRun = minId;start = lastTime;}//运行进程 int run = que[tmp].comeTime - lastTime;//进程能运行完就运行完 if (run >= que[isRun].runTime || run <= 0){lastTime += que[isRun].runTime;que[isRun].order = ID++;que[isRun].beginTime = start;que[isRun].endTime = lastTime;printf("%d/%d/%d/%d/%d\n", que[isRun].order, que[isRun].pid, que[isRun].beginTime, que[isRun].endTime, que[isRun].priority);que[isRun].runTime = 0;que[isRun].finish = IsEnd;counts++;isRun = -1;start = lastTime;}//进程不能运行完就运行一个时间片 else{lastTime += run;que[isRun].runTime -= run;}}
}
void RR()
{sort(que, que + num, cmp1);queue<process>q;//就绪队列 int lastTime = 0;//当前时间 int ID = 1;//输出顺序 int tmp = 0, counts = 0;//当前进程,输出次数 while (counts < num){if (q.empty())//队列为空则等待进程到来 {lastTime = que[tmp].comeTime;while (que[tmp].comeTime <= lastTime && tmp < num)//当前时间内的进程 {if (que[tmp].finish == NoEnd)//还没完成的进程入队 {q.push(que[tmp]);}tmp++;}}else{process ans = q.front();//取出处于队列头的进程 q.pop();//进程可以运行完 if (ans.runTime <= ans.slot){//输出当前进程调度 ans.order = ID++;ans.beginTime = lastTime;ans.endTime = ans.beginTime + ans.runTime;printf("%d/%d/%d/%d/%d\n", ans.order, ans.pid, ans.beginTime, ans.endTime, ans.priority);lastTime = ans.endTime;//更新当前时间 ans.finish = IsEnd;//标记短作业结束 counts++;while (que[tmp].comeTime <= lastTime && tmp < num)//当前时间内的进程 {if (que[tmp].finish == NoEnd)//还没完成的进程入队 {q.push(que[tmp]);}tmp++;}}//进程不能运行完 else{//输出当前进程调度 ans.order = ID++;ans.beginTime = lastTime;ans.endTime = ans.beginTime + ans.slot;printf("%d/%d/%d/%d/%d\n", ans.order, ans.pid, ans.beginTime, ans.endTime, ans.priority);lastTime = ans.endTime;ans.runTime -= ans.slot;while (que[tmp].comeTime <= lastTime && tmp < num)//当前时间内的进程 {if (que[tmp].finish == NoEnd)//还没完成的进程入队 {q.push(que[tmp]);}tmp++;}q.push(ans);//先让新进程入队再让当前进程入队 }}}
}
void DPSA()
{sort(que, que + num, cmp1);int lastTime = que[0].comeTime;//当前时间 int ID = 1;//输出顺序 int tmp = 0, counts = 0;//当前进程,输出次数 int start = lastTime;//当前进程开始时间 int minId, Smin;while (counts < num){while (que[tmp].comeTime <= lastTime && tmp < num)//当前时间内的进程 {if (que[tmp].comeTime > start && que[tmp].comeTime < lastTime){que[tmp].priority = max(que[tmp].priority - 1, 0);//等待时优先级加1 }tmp++;}//寻找最高优先级进程 minId = -1;Smin = 0x3f3f3f;for (int i = 0; i < tmp; i++){if (que[i].priority < Smin && que[i].finish == NoEnd){Smin = que[i].priority;minId = i;}}if (minId == -1)//如果当前时间进程都结束了就等待下一个进程 {lastTime = que[tmp].comeTime;continue;}//运行进程 start = lastTime;//进程能运行完 if (que[minId].runTime <= que[minId].slot){que[minId].order = ID++;que[minId].beginTime = lastTime;que[minId].endTime = lastTime + que[minId].runTime;printf("%d/%d/%d/%d/%d\n", que[minId].order, que[minId].pid, que[minId].beginTime, que[minId].endTime, que[minId].priority + 3);counts++;lastTime += que[minId].runTime;que[minId].finish = IsEnd;}//进程不能运行完 else{que[minId].order = ID++;que[minId].beginTime = lastTime;que[minId].endTime = lastTime + que[minId].slot;printf("%d/%d/%d/%d/%d\n", que[minId].order, que[minId].pid, que[minId].beginTime, que[minId].endTime, que[minId].priority + 3);lastTime += que[minId].slot;que[minId].runTime -= que[minId].slot;}//改变进程优先级 for (int i = 0; i < tmp; i++){if (que[i].finish == NoEnd){if (i == minId)//运行优先级减3 {que[i].priority += 3;}else//等待优先级加1 {que[i].priority = max(que[i].priority - 1, 0);}}}}
}
bool cmp1(process a, process b)
{if (a.comeTime != b.comeTime)return a.comeTime < b.comeTime;elsereturn a.pid < b.pid;
}
bool cmp2(process a, process b)
{if (a.comeTime != b.comeTime)return a.comeTime < b.comeTime;else if (a.runTime != b.runTime)return a.runTime > b.runTime;elsereturn a.pid < b.pid;
}

测试结果

程序采用黑盒测试的方式,提交到乐学的 OJ 系统上进行在线评测

可以看到,OJ 的测试用例全部通过

心得体会

通过本次实验,上机代码模拟实现了五种进程调度算法,对操作系统内部的进程调度方式有了更深刻的认识和感受。对于非剥夺的短作业优先算法而言,因为每次都要检测当前时刻的短作业,排序其实可有可无;对于其余四种算法而言,排序则显得尤为重要。

操作系统实验1—实现单处理机下的进程调度程序相关推荐

  1. 操作系统实验报告4:Linux 下 x86 汇编语言3

    操作系统实验报告4 实验内容 验证实验 Blum's Book: Sample programs in Chapter 08, 10 (Basic Math Functions and Using S ...

  2. 操作系统实验报告3:Linux 下 x86 汇编语言2

    操作系统实验报告3 实验内容 验证实验 Blum's Book: Sample programs in Chapter 06, 07 (Controlling Flow and Using Numbe ...

  3. 操作系统实验报告2:Linux 下 x86 汇编语言1

    操作系统实验报告2 实验内容 了解 Linux 下 x86 汇编语言编程环境: 验证实验 Blum's Book: Sample programs in Chapter 04, 05 (Moving ...

  4. 操作系统——实验壹——熟悉Linux基础命令及进程管理

    一. 实验目的 加深对进程概念的理解,明确进程和程序的区别. 进一步认识并发执行的实质. 分析进程争用资源的现象,学习解决进程互斥的方法. 二. 实验内容 运行程序,查看自己运行的结果,并进行分析. ...

  5. 计算机操作系统32,计算机操作系统实验指导书32138

    计算机操作系统实验指导书32138 (22页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 <计算机操作系统>实验指导书程科白素 ...

  6. 处理机调度实验c语言,操作系统实验处理机调度C语言实现

    操作系统实验处理机调度C语言实现 下载提示(请认真阅读)1.请仔细阅读文档,确保文档完整性,对于不预览.不比对内容而直接下载带来的问题本站不予受理. 2.下载的文档,不会出现我们的网址水印. 3.该文 ...

  7. c语言处理机调度实验报告,操作系统实验处理机调度C语言实现.docx

    操作系统实验处理机调度C语言实现.docx 下载提示(请认真阅读)1.请仔细阅读文档,确保文档完整性,对于不预览.不比对内容而直接下载带来的问题本站不予受理. 2.下载的文档,不会出现我们的网址水印. ...

  8. 操作系统算法模拟实例之单处理机系统进程调度

    操作系统算法模拟实例之单处理机系统进程调度 1.实验目的 在多道程序或多任务系统中,系统回时处于就绪态的进程有若干个,为使系统中 的各进程能有条不素地运行,必须选择某种调度策略,以选择一进程占用处理机 ...

  9. linux应用程序的编写实验原理,操作系统实验 1.在linux下编写一个应用程序 联合开发网 - pudn.com...

    操作系统实验 所属分类:Linux/Unix编程 开发工具:C/C++ 文件大小:1KB 下载次数:3 上传日期:2019-05-01 20:34:21 上 传 者:烟雨南风起 说明:  1.在lin ...

最新文章

  1. 何时开学?教育部最新回应:满足三个条件可开学
  2. redis和memcached的区别(总结)
  3. 中文文本纠错 算例实现(有算例完整代码)
  4. 获取一个窗口的所有子窗口(包括嵌套) - 回复 asian 的问题
  5. 【机器学习】特征工程七种常用方法
  6. SQL Server on Ubuntu——Ubuntu上的SQL Server(全截图)
  7. spring(四):spring与mybatis结合
  8. java 大小固定_为什么Java堆的最大大小是固定的?
  9. php和c语言的字符数组中,字符数组和字符串的区别,C语言字符数组和字符串区别详解...
  10. php 循环中return,php中for循环遇上return的示例代码分享
  11. 《Lucene in Action》 MoreLikeThis 实例
  12. php 怎么输入php ini,PHP怎么找到php.ini配置文件?-php教程
  13. 徐小湛概率论与数理统计课件_考研数学 徐小湛教授线性代数90讲
  14. 两种方法,word文件转换成PDF文件
  15. 技术人应该如何提升影响力
  16. 了解计算机病毒及杀毒方式,最简易的计算机病毒查杀方法
  17. 移动定位业务之“A-GPS(辅助全球卫星定位系统)”
  18. S700K转辙机多机牵引道岔故障处理【转自微信公众号高速铁路信号技术交流】
  19. php global 要点
  20. Python经典编程习题100例:第20例:落体反弹问题

热门文章

  1. Git : 将本地git仓库同步到远端github上
  2. 处理被中断的系统调用
  3. 软件测试-TC用户模板导入不成功
  4. 怎样通过css控制table的部分td
  5. property field java_Java 中 field 和 variable 区别及相关术语解释
  6. oracle standby同步,ORACLE 利用rman增量备份同步standby库
  7. mysql数据库试题下载_MYSQL数据库2013-2014学年考试试卷
  8. 基于连通域字符分割的流程_基于OpenCV及连通域分析进行文本块分割
  9. 云计算灾备:灾备通识
  10. 阿里展示首个IDC智能机器人 实现人机合作