一、进程调度算法的背景

在多道程序环境下,内存中存在着多个进程,其数目往往多于处理机数目。这就要求系统能按某种算法,动态地将处理机分配给处于就绪状态的一个进程,使之执行。分配处理机的任务是由处理机调度程序完成的。对于大型系统运行时的性能,如系统吞吐量、资源利用率、作业周转时间或响应的及时性等,在很大程度上都取决于处理机调度性能的好坏。因而,处理机调度便成为OS中至关重要的部分。
了解进程调度算法可以更好的理解操作系统是如何将资源合理的分配给各个正在运行的进程。理解三种进程调度算法可以充分利用计算机系统中的CPU资源,让计算机系统能够多快好省地完成我们让它做的各种任务。为此,可在内存中可存放数目远大于计算机系统内CPU个数的进程,让这些进程在操作系统的进程调度器的调度下,能够让进程高效、及时、公平地使用CPU。为此调度器可设计不同的调度算法来选择进程,这体现了进程调度的策略,同时还需并进一步通过进程的上下文切换来完成进程切换,这体现了进程调度的机制。了解上述细节,也就可以说是了解了进程调度。

二、进程点调度算法的原理

1.先来先服务算法(FCFS)

先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为它们分配资源、创建进程,然后放入就绪队列。在进程调度中采用FCFS算时,则每次调度是从就绪队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行。该进程一直运行到完成或发生某事件而阻塞后才放弃处理机。


2.短作业优先算法(SJF)

短作业(进程)优先调度算法SJ(P)F,是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。而短进程优先(SPF)调度算法则是从就绪队列中选出一个估计运行时间最短的进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时再重新调度。

3.时间片轮转算法(RR)

在时间片轮转调度算法中,系统根据先来先服务的原则,将所有的就绪进程排成一个就绪队列,并且每隔一段时间产生一次中断,激活系统中的进程调度程序,完成一次处理机调度,把处理机分配给就绪队列队首进程,让其执行指令。当时间片结束或进程执行结束,系统再次将cpu分配给队首进程。

三、各个算法的实验数据

1.FCFS算法:

进程:ABCDE,
到达时间分别为:0,1,2,3,4
服务时间分别为:4,3,4,2,4
执行结果如下:

2.SJF算法:

测试(1):
进程:A,B,C
到达时间分别为:0,1,5,
服务时间分别为:3,1,2,
执行结果如下

测试(2):
进程:A,B,C,
到达时间分别为:0,3,3
服务时间分别为:2,4,2
执行结果如下:

测试(3):
进程:ABCDE
到达时间分别为:0,1,2,3,4
服务时间分别为:4,3,4,2,4
执行结果如下:

3.RR算法:

测试(1):
时间片 q =1时
进程:ABCDE
到达时间分别为:0,1,2,3,4
服务时间分别为:4,3,4,2,4
执行结果如下:

测试(2):
时间片 q =4
进程:ABCDE
到达时间分别为:0,1,2,3,4
服务时间分别为:4,3,4,2,4
执行结果如下:

四、算法的优劣比较

对于测试用例:
进程:ABCDE
到达时间分别为:0,1,2,3,4
服务时间分别为:4,3,4,2,4
三个算法都测试过了,下面是各个算法的对比。

可见,在此测试用例中,平均周转时间最短的是SJF算法,平均周转时间最长的是RR算法(q=1)。

1、先来先服务调度算法(FCFS):根据进程到达的先后顺序执行进程,不考虑等待时间和执行时间,会产生饥饿现象。属于非抢占式调度,优点是公平,实现简单;缺点是不利于短作业。

2、短作业优先算法(SJF):由上图中可以看出,采用SJF算法后,不论是平均周转时间还是平均带权周转时间,都有较明显的改善,尤其是对短作业,其周转时间减小,这说明SJF调度算法能有效地降低作业的平均等待时间,提高系统吞吐量。SJF调度算法也存在不容忽视的缺点:该算法对长作业不利,如果有一长作业(进程)进入系统的后备队列(就绪队列),由于调度程序总是优先调度那些(即使是后进来的)短作业(进程),将导致长作业(进程)长期不被调度。该算法完全未考虑作业的紧迫程度,因而不能保证紧迫性作业(进程)会被及时处理。由于作业(进程)的长短只是根据用户所提供的估计执行时间而定的,而用户又可能会有意或无意地缩短其作业的估计运行时间,致使该算法不一定能真正做到短作业优先调度。

3、时间片轮转调度算法(RR):在轮转调度算法中时间片的大小对系统的性能有很大的影响。若时间片很小,将有利于短作业,其能够在这个时间片内完成。时间片过小意味着会进行频繁的进程切换,这将增大系统的开销。若时间片选择太长,时间片轮转调度算法将退化为先来先服务的进程调度算法。属于抢占式调度。优点是兼顾长短作业;缺点是平均等待时间较长,上下文切换较费时。

五、代码实现

Pcb.h

#pragma once
#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<fstream>
#include<functional>
using namespace std;#define BEREADY 0 //就绪状态
#define RUNNING 1 //运行状态
#define WAITING 2 //等待状态class PCB
{private:string m_PidName; //进程名int m_Arrival; //进程到达时间int m_Server; //进程运行时间int m_Finish;//进程完成时间int m_Turnaround;//周转时间float m_Weighted;//带权周转时间int m_Status;//运行状态static float m_s_AverTurnaround;//平均周转时间static float m_s_AverWeighted;//平均带权周转时间static int m_s_Num;//进程数量public:friend void FCFS();friend void SJF();friend void RR();friend void ReadData();static void OutputPid(PCB* P, int num);
};void ReadData();//读入数据
void FCFS();
void SJF();
void RR();

Pcb.cpp

#include"PCB.h"float PCB::m_s_AverTurnaround = 0;//平均周转时间
float PCB::m_s_AverWeighted = 0;//平均带权周转时间
int PCB::m_s_Num = 0;//进程数量
PCB *Pid;void ReadData()//读入数据
{ifstream readData;readData.open("data.txt");readData >> PCB::m_s_Num;//读入分区数量  Pid = new PCB[PCB::m_s_Num];//开空间for (int i = 0; i < PCB::m_s_Num; i++)//读入进程名称{readData >> Pid[i].m_PidName;}for (int i = 0; i < PCB::m_s_Num; i++)//读入进程到达时间{readData >> Pid[i].m_Arrival;}for (int i = 0; i < PCB::m_s_Num; i++)//读入进程运行时间{readData >> Pid[i].m_Server;}readData.close();
}void PCB::OutputPid(PCB* P, int num)
{printf("\n%-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s\n\n", "进程名", "到达时间", "运行时间", "完成时间", "周转时间", "带权周转时间", "平均周转时间", "平均带权周转时间");for (int i = 0; i < num; i++){cout << P[i].m_PidName << "\t  " << P[i].m_Arrival << "\t  " << P[i].m_Server << "\t    " << P[i].m_Finish << "\t    " << P[i].m_Turnaround << "\t    " << P[i].m_Weighted;if (i + 1 == num){printf(" \t\t%3.2f\t  %3.2f\n\n", PCB::m_s_AverTurnaround, PCB::m_s_AverWeighted);}cout << endl;}
}void FCFS()
{int num, T;cout << "-------------FCFS算法-------------\n\n\n";ReadData();num = PCB::m_s_Num;multimap<int, PCB*> m;for (int i = 0; i < num; i++){m.insert(make_pair(Pid[i].m_Arrival, Pid + i));}T = Pid[0].m_Arrival;for (auto& ip = m.begin(); ip != m.end();){PCB* tmp = ip->second;if (T >= tmp->m_Arrival)//上一个进程进行中这个进程已经到了内存{tmp->m_Finish = T + tmp->m_Server;T += tmp->m_Server;}else//map里的进程空了,直接执行下一个,T要加上等待时间(m_Arrival - T){tmp->m_Finish = T + tmp->m_Server + (tmp->m_Arrival - T);T += tmp->m_Server + (tmp->m_Arrival - T);}tmp->m_Turnaround = tmp->m_Finish - tmp->m_Arrival;tmp->m_Weighted = (float)tmp->m_Turnaround / (float)tmp->m_Server;PCB::m_s_AverTurnaround += tmp->m_Turnaround;PCB::m_s_AverWeighted += tmp->m_Weighted;cout << "时刻" << T << ",进程" << tmp->m_PidName << "完成,退出" << endl;ip = m.erase(ip);}PCB::m_s_AverTurnaround /= (float)num;PCB::m_s_AverWeighted /= (float)num;PCB::OutputPid(Pid, num);
}void SJF()
{int num, T;cout << "-------------SJF算法-------------\n\n\n";ReadData();num = PCB::m_s_Num;multimap<int, PCB*> ma;//ma--按到达时间排序for (int i = 0; i < num; i++){ma.insert(make_pair(Pid[i].m_Arrival, Pid + i));//最先进入时间}T = ma.begin()->second->m_Arrival;//开始时刻是先到达的那个进程的到达时间for (auto& ip = ma.begin(); !ma.empty();)//跳出条件是m2为空{PCB* tmp = ip->second;//记录ip->second的值,减少代码的冗余,进入后ip改变,不能使用tmpif (T >= tmp->m_Arrival)//进程到达{auto ip1 = ip;int MinServer1 = ip->second->m_Server;ip++;while (ip != ma.end() && T >= ip->second->m_Arrival)//找到已到达进程中的最小服务时间{if (ip->second->m_Server < MinServer1){MinServer1 = ip->second->m_Server;ip1 = ip;}else{ip++;}}ip = ip1;tmp = ip->second;//记录ip->second的值,减少代码的冗余tmp->m_Finish = T + tmp->m_Server;T += tmp->m_Server;}else//运行完进程A之后,其他进程还未到达等待队列中且满足是最小服务时间{auto ip2 = ip;int MinServer2 = ip->second->m_Server;int t = ip->second->m_Arrival;ip++;while (ip != ma.end() && t == ip->second->m_Arrival)//找到已到达进程中的最小服务时间{if (ip->second->m_Server < MinServer2){MinServer2 = ip->second->m_Server;ip2 = ip;}else{ip++;}}ip = ip2;tmp = ip->second;//记录ip->second的值,减少代码的冗余tmp->m_Finish = T + tmp->m_Server + (tmp->m_Arrival - T);//完成时间等于上一个进程的完成时间+要等待的时间(tm->m_Arrival-T)+需要运行的时间T += tmp->m_Server + (tmp->m_Arrival - T);//时刻T也要加上等待时间}tmp->m_Turnaround = tmp->m_Finish - tmp->m_Arrival;tmp->m_Weighted = (float)tmp->m_Turnaround / (float)tmp->m_Server;PCB::m_s_AverTurnaround += tmp->m_Turnaround;PCB::m_s_AverWeighted += tmp->m_Weighted;cout << "时刻" << T << ",进程" << tmp->m_PidName << "完成,退出" << endl;ip = ma.erase(ip);ip = ma.begin();//每次从ma的头部(即最先到达的进程找起)}PCB::m_s_AverTurnaround /= (float)num;PCB::m_s_AverWeighted /= (float)num;PCB::OutputPid(Pid, num);
}void RR()
{int q = 0;int num, T;queue<PCB*> qu;PCB* cur;typedef struct{int Arrival;int Server;}tmp;map<string, tmp*> ma;cout << "-------------RR算法-------------\n\n\n";ReadData();num = PCB::m_s_Num;tmp * t = new tmp[num];cout << "设置时间片:";cin >> q;for (int i = 0; i < num; i++)//先使所有进程处于等待状态{t[i].Arrival = Pid[i].m_Arrival;t[i].Server = Pid[i].m_Server;ma.insert(make_pair(Pid[i].m_PidName,t + i));//将所有到达时间保存,在进程运行时会修改,运行完重新赋回去Pid[i].m_Status = WAITING;}T = Pid[0].m_Arrival;//取第一个到达内存的进程pqu.push(Pid);while (!qu.empty())//ma为空,轮转完毕{cur = qu.front();cur->m_Status = RUNNING;//拿到时间片状态标志位改变为RUNNINGif (cur->m_Server - q == 0)//刚好减完{T += q;cout << "时刻" << T << ",进程" << cur->m_PidName << "完成,退出" << endl;cur->m_Finish = T;cur->m_Turnaround = cur->m_Finish - ma[cur->m_PidName]->Arrival;cur->m_Weighted = (float)(cur->m_Turnaround) / (float)(ma[cur->m_PidName]->Server);PCB::m_s_AverTurnaround += cur->m_Turnaround;PCB::m_s_AverWeighted += cur->m_Weighted;cur->m_Server = 0;//输出完以后置为0,防止再次调用}else if (cur->m_Server - q > 0){T += q;cur->m_Arrival += q;//到达时间也跟着变化cur->m_Server -= q;}else//剩余服务时间超过时间片{T += cur->m_Server;cout << "时刻" << T << ",进程" << cur->m_PidName << "完成,退出" << endl;cur->m_Finish = T;cur->m_Turnaround = cur->m_Finish - ma[cur->m_PidName]->Arrival;cur->m_Weighted = (float)(cur->m_Turnaround) / (float)(ma[cur->m_PidName]->Server);cur->m_Server = 0;//输出完以后置为0,防止再次调用PCB::m_s_AverTurnaround += cur->m_Turnaround;PCB::m_s_AverWeighted += cur->m_Weighted;}qu.pop();//运行完就pop掉for (int i = 0; i < num ; i++)//将在上一个进程运行时间内和运行完这段时间中所有到达的进程push进队{if (T >= Pid[i].m_Arrival && Pid[i].m_Status == WAITING){qu.push(Pid + i);qu.back()->m_Status = BEREADY;//让其处于就绪队列中}}if (cur->m_Server != 0)//这个进程运行完后判断是否结束,没结束就加入队尾{qu.push(cur);cur->m_Status = BEREADY;//让其处于就绪队列中}}for (int i = 0; i < num; i++){Pid[i].m_Arrival = ma[Pid[i].m_PidName]->Arrival;//将保存的值赋回去Pid[i].m_Server = ma[Pid[i].m_PidName]->Server;}PCB::m_s_AverTurnaround /= (float)num;PCB::m_s_AverWeighted /= (float)num;PCB::OutputPid(Pid, num);
}

Main.cpp

#include"PCB.h"
#include<iostream>
using namespace std;int chose;while (1){cout << "-------进程调度算法-------" << endl << endl << endl;cout << "------1.FCFS" << endl;cout << "------2.SJF" << endl;cout << "------3.RR" << endl;cin >> chose;switch (chose){case 1:FCFS();break;case 2:SJF();break;case 3:RR();break;default:cout << "输入错误!!!" << endl;}}system("pause");return 0;
}

进程分配算法(FCFS,SJF,RR)相关推荐

  1. Java模拟操作系统实验一:四种进程调度算法实现(FCFS,SJF,RR,HRN)

    前言 刚学完操作系统,模拟实现了其中一些经典的算法,内容比较多,打算写一个系列的总结,将自己的源码都分享出来,既方便自己以后复习,也希望能帮助到一些刚入坑的小伙伴.我的所有代码的运行环境都是基于Ecl ...

  2. 操作系统实验二——进程调度算法(FCFS、RR)

    目录 进程调度算法 FCFS算法代码 RR算法代码 进程调度算法 FCFS算法代码 #include <stdio.h> #include <string.h> #includ ...

  3. 进程调度c语言 fcfs,计算机进程调度算法FCFS、RR、SJF的实现

    调度算法,在Linux环境下用C语言编写程序,模拟FCFS.RR.SJF等进程调度算法,以及利用信号量等方法解决哲学家就餐问题. 在主进程中,创建 20 个子线程,分别模拟进程调度算法FCFS.RR. ...

  4. 进程调度算法——C++实现 [ FCFS,SJF,HPR,HRN + 开源代码 + 详细解析 ]

    ✅ (原创,库存,第100篇博客,纪念一下) 文章目录 零.动态演示图 一.实现原理 二.实现内容: 三.算法流程图: 3.1 先来先服务算法(FCFS)的流程图: 3.2 最短作业优先算法(SJF) ...

  5. 进程调度算法FCFS和RR

    一. 实验题目 本次试验要求编写的是进程调度中的FCFS算法和RR算法(轮转法). FCFS算法:最简单的CPU调度算法,采取先到先服务的规则,不存在进程优先级之说,也不管进程服务时间的长短,只有前面 ...

  6. 操作系统(五):FCFS/SJF/非抢占优先级/RR

    操作系统(五):FCFS/SJF/非抢占优先级/RR 一.题目1(书上170页5.7) 5.4 5.4 Consider the following set of processes, with th ...

  7. 一、操作系统——处理机(作业)调度算法:先来先服务算法FCFS、最短作业优先算法SJF(非抢占式)、 最短剩余时间优先算法SRTN(抢占式)、最高响应比优先算法HRRN

    各种调度算法的学习思路: 调度算法的评价指标: 一.先来先服务算法(FCFS):First Come First Serve 二.最短作业优先算法(SJF非抢占式):Shortest Job Firs ...

  8. FCFS,SJF以及PSA进程调度算法效率的比较

    实现 下面是用 Java 程序比较 FCFS,SJF 和 PSA 算法效率的示例代码: FCFS 思路 对于 FCFS 算法,我们可以定义一个 Process 类来表示一个进程,其中包含进程名称.到达 ...

  9. FCFS,SJF以及PSA进程调度算法的比较

    实现 下面是用 Java 程序比较 FCFS,SJF 和 PSA 算法效率的示例代码: FCFS 思路 对于 FCFS 算法,我们可以定义一个 Process 类来表示一个进程,其中包含进程名称.到达 ...

最新文章

  1. 深度分析:比特大陆二代AI芯片性能跃升,专注安防视频
  2. 2022年想成为软件测试工程师,这个学习路线收藏起来
  3. java操作dom节点的添加_java操作DOM节点的添加,删除,修改
  4. Windows Server 2003 R2 修复Windows Server 2003
  5. pygame从入门到提高(2)-平铺背景
  6. args和kwargs以及argv用法
  7. oracle将查询结果声明为伪表,Oracle的伪列和伪表
  8. 国产操作系统发展离不开人才和市场
  9. 12如何隐藏dock栏_iPhone边框“变色”壁纸,隐藏Dock栏
  10. 与Maven和Docker的集成测试
  11. [剑指offer]面试题第[67]题[Leetcode][JAVA][第8题] 字符串转换整数 (atoi)[字符串]
  12. 云云协同解决方案全景图发布 华为云助力科技企业云上创新
  13. linux coreutils升级,Coreutils
  14. PHP+nginx安装配置注意事项
  15. 安装这些App的注意了!隐私窃取 捆绑推广 已被下架 现在卸载还来得及!
  16. concatenate python_python中numpy.concatenate()函数的使用
  17. 词汇的积累与遣词造句 —— 准确的表达、新鲜的词汇
  18. ROST情感分析的语法规则_用c语言手搓一个600行的类c语言解释器: 给编程初学者的解释器教程(4)- 语法分析1...
  19. 今日头条关键词文章热度和搜索指数的查询方法分享
  20. 小智机器人有初中课程吗_张小智

热门文章

  1. 破局 | STO 会是P2P不良资产包化解难的救星吗?
  2. Java web - 黑马旅游网(加使用文档总结)
  3. python3 爬取乐谱
  4. 【论文学习】YOLO v1
  5. 启锐5xx和4xx系列打印机驱动ver2.2.0_2020年十一月 三合一彩色喷墨打印机对比及推荐...
  6. 新员工培训需要经过哪些步骤和流程
  7. Windows系统下QT+OpenCasCAD仿真开发
  8. 解密犯罪时间JAVA
  9. RFID资产管理软件可进行哪些管理
  10. WGS 2019:世界政府峰会无疑是全球重要改变的催化剂