一、实验内容
问题描述:
设计程序模拟进程的先来先服务FCFS和短作业优先SJF调度过程。假设有n个进程分别在T1, … ,Tn时刻到达系统,它们需要的服务时间分别为S1, … ,Sn。分别采用先来先服务FCFS和短作业优先SJF进程调度算法进行调度,计算每个进程的完成时间,周转时间和带权周转时间,并且统计n个进程的平均周转时间和平均带权周转时间。
程序要求如下:
1)进程个数n;每个进程的到达时间T1, … ,Tn和服务时间S1, … ,Sn;选择算法1-FCFS,2-SJF。
2)要求采用先来先服务FCFS和短作业优先SJF分别调度进程运行,计算每个进程的周转时间,带权周转时间,并且计算所有进程的平均周转时间,带权平均周转时间;
3)输出:要求模拟整个调度过程,输出每个时刻的进程运行状态,如“时刻3:进程B开始运行”等等;
4)输出:要求输出计算出来的每个进程的周转时间,带权周转时间,所有进程的平均周转时间,带权平均周转时间。
二、完整代码
#include <iostream>
#include <queue>
#include<string.h>
#include<algorithm>
#include <stdlib.h>
using namespace std;
float getAvg(float f[5]) {
float sum = 0.0;
for (int i = 0; i < 5; i++) {
sum += f[i];
}
return sum/5.0;
}
int main() {
float arriveTime[5] = {0,1,2,3,4};
float serveTime[5] = {4,3,5,2,4};
int c[5];
float finishTime1[5] = {0}, finishTime2[5], circleTime1[5], circleTime2[5], weightTime1[5], weightTime2[5];
for(int i = 0; i < 5; i++){
if(i == 0){
finishTime1[i] = finishTime1[0] + serveTime[0];
circleTime1[i] = finishTime1[0] - arriveTime[0];
weightTime1[i] = circleTime1[0] / serveTime[0];
} else {
finishTime1[i] = finishTime1[i-1] + serveTime[i];
circleTime1[i] = finishTime1[i] - arriveTime[i];
weightTime1[i] = circleTime1[i] / serveTime[i];
}
}
for(int i = 0; i < 5; i++) {
if(i == 0) {
finishTime2[i] = finishTime2[0] + serveTime[0];
circleTime2[i] = finishTime2[0] - arriveTime[0];
weightTime2[i] = circleTime2[0] / serveTime[0];
} else {
float temp = serveTime[i];
int j, minIndex;
//获取当前服务时间最短的进程下标
for(j = 1; j < 5; j++) {
temp = min(serveTime[j], temp);
if(serveTime[j] <= temp ) {
minIndex = j;
}
}
c[i] = minIndex;
finishTime2[i] = finishTime2[i-1] + serveTime[minIndex];
circleTime2[i] = finishTime2[i] - arriveTime[minIndex];
weightTime2[i] = circleTime2[i] / serveTime[minIndex];
//将服务结束的进程服务时间设为无穷大
serveTime[minIndex] = 9999;
}
}
cout<<"FCFS算法"<<endl<<"完成时间:";
for(int i = 0; i < 5; i++) {
cout<<finishTime1[i]<<" ";
}
cout<<endl<<"周转时间:";
for(int i = 0; i < 5; i++) {
cout<<circleTime1[i]<<" ";
}
cout<<endl<<"带权周转时间:";
for(int i = 0; i < 5; i++) {
cout<<weightTime1[i]<<" ";
}
cout<<endl<<"平均周转时间:"<<getAvg(circleTime1)<<endl;
cout<<"平均带权周转时间:"<<getAvg(weightTime1)<<endl;
cout<<endl<<endl<<"SJF算法"<<endl<<"完成时间:";
for(int i = 0; i < 5; i++) {
cout<<finishTime2[c[5-i]]<<" ";
}
cout<<endl<<"周转时间:";
for(int i = 0; i < 5; i++) {
cout<<circleTime2[c[5-i]]<<" ";
}
cout<<endl<<"带权周转时间:";
for(int i = 0; i < 5; i++) {
cout<<weightTime2[c[5-i]]<<" ";
}
cout<<endl<<"平均周转时间:"<<getAvg(circleTime2)<<endl;
cout<<"平均带权周转时间:"<<getAvg(weightTime2)<<endl;
system("pause");
return 0;
}
三、代码说明
1.定义输入数据
float arriveTime[5] = {0,1,2,3,4};
float serveTime[5] = {4,3,5,2,4};
2.定义进程相关变量
float finishTime1[5] = {0}, finishTime2[5], circleTime1[5], circleTime2[5], weightTime1[5], weightTime2[5];
变量说明
finishTime1 | FCFS算法完成时间 |
finishTime2 | SJF算法完成时间 |
circleTime1 | FCFS算法周转时间 |
circleTime2 | SJF算法周转时间 |
weightTime1 | FCFS算法带权周转时间 |
weightTime2 | SJF算法带权周转时间 |
3.计算FCFS算法中的完成时间、周转时间和带权周转时间。
其中,对于循环第一次的完成时间需要特殊处理,时间复杂度为O(n)
for(int i = 0; i < 5; i++){
if(i == 0){
finishTime1[i] = finishTime1[0] + serveTime[0];
circleTime1[i] = finishTime1[0] - arriveTime[0];
weightTime1[i] = circleTime1[0] / serveTime[0];
} else {
finishTime1[i] = finishTime1[i-1] + serveTime[i];
circleTime1[i] = finishTime1[i] - arriveTime[i];
weightTime1[i] = circleTime1[i] / serveTime[i];
}
}
4.计算SJF算法中的完成时间、周转时间和带权周转时间。
其中,对于循环第一次的完成时间需要特殊处理。
需要注意的是,SJF算法需要让服务时间最短的进程优先进入队列,因此需要内嵌循环,计算每一轮服务时间最短的进程。因此,时间复杂度为O(n2).
for(int i = 0; i < 5; i++) {
if(i == 0) {
finishTime2[i] = finishTime2[0] + serveTime[0];
circleTime2[i] = finishTime2[0] - arriveTime[0];
weightTime2[i] = circleTime2[0] / serveTime[0];
} else {
float temp = serveTime[i];
int j, minIndex;
//获取当前服务时间最短的进程下标
for(j = 1; j < 5; j++) {
temp = min(serveTime[j], temp);
if(serveTime[j] <= temp ) {
minIndex = j;
}
}
c[i] = minIndex;
finishTime2[i] = finishTime2[i-1] + serveTime[minIndex];
circleTime2[i] = finishTime2[i] - arriveTime[minIndex];
weightTime2[i] = circleTime2[i] / serveTime[minIndex];
//将服务结束的进程服务时间设为无穷大
serveTime[minIndex] = 9999;
}
}
5.输出FCFS算法结果
cout<<"FCFS算法"<<endl<<"完成时间:";
for(int i = 0; i < 5; i++) {
cout<<finishTime1[i]<<" ";
}
cout<<endl<<"周转时间:";
for(int i = 0; i < 5; i++) {
cout<<circleTime1[i]<<" ";
}
cout<<endl<<"带权周转时间:";
for(int i = 0; i < 5; i++) {
cout<<weightTime1[i]<<" ";
}
cout<<endl<<"平均周转时间:"<<getAvg(circleTime1)<<endl;
cout<<"平均带权周转时间:"<<getAvg(weightTime1)<<endl;
6.输出SJF算法结果
由于在上面的循环中,每一次获取服务时间最小值下标会打乱进程顺序,因此需要用数组c[5]保存下标,从而顺序输出。
cout<<endl<<endl<<"SJF算法"<<endl<<"完成时间:";
for(int i = 0; i < 5; i++) {
cout<<finishTime2[c[5-i]]<<" ";
}
cout<<endl<<"周转时间:";
for(int i = 0; i < 5; i++) {
cout<<circleTime2[c[5-i]]<<" ";
}
cout<<endl<<"带权周转时间:";
for(int i = 0; i < 5; i++) {
cout<<weightTime2[c[5-i]]<<" ";
}
cout<<endl<<"平均周转时间:"<<getAvg(circleTime2)<<endl;
cout<<"平均带权周转时间:"<<getAvg(weightTime2)<<endl;
四、结果展示
五、总结
本次实验中,我使用C++代码来模拟FCFS和SJF两种调度算法,根据输入的到达时间和服务时间作为测试数据,实现两种算法的执行顺序,从而得到结果。
FCFS算法作为较简单的调度算法,其原理比较简单,根据到达时间的先后顺序,决定进程进入队列的优先级,之后每取出一个进程,便依次计算其完成时间、周转时间、带权周转时间,最后得出平均周转时间和平均带权周转时间即可。
SJF算法需要根据服务时间来决定优先级,服务时间最短的进程,优先进入队列,因此需要在每个进程达到后,获取当前时间最短服务时间的进程,让该进程进入队列。并计算完成时间、周转时间、带权周转时间,最后得出平均周转时间和平均带权周转时间。而且在输出时,要注意顺序不能错乱,根据初始下标输出便得到结果。
本次实验使我理解了线程的两种调度方式,很明显SJF算法更贴近实际应用,结果也表明SJF的平均周转时间和平均带权周转时间都小于FCFS算法,但实现起来也比FCFS算法要更为复制,两种调度算法各有各的特性,更有利于我理解进程调度的含义。