实验三
【实验题目】:高响应比优先调度和时间片轮转RR进程调度算法
【实验目的】
通过这次实验,加深对进程调度概念的理解,进一步掌握比FCFS和SJF更为复杂的进程调度算法的实现方法。
【实验内容及要求】
算法思路:
时间片轮转RR进程调度算法:用于分时系统中的进程调度。每次调度时,总是选择就绪队列的队首进程,让其在CPU上运行一个系统预先设置好的时间片。一个时间片内没有完成运行的进程,返回到绪队列末尾重新排队,等待下一次调度。
给每个进程固定的执行时间,根据进程到达的先后顺序让进程在单位时间片内执行,执行完成后便调度下一个进程执行,时间片轮转调度不考虑进程等待时间和执行时间,属于抢占式调度。优点是兼顾长短作业;缺点是平均等待时间较长,上下文切换较费时。适用于分时系统。
高响应比优先算法:①当等待时间相同时,短进程的优先权高;②当需要运行时间相同时,作业的优先权又取决于等待时间,相当于先到先服务;③长作业的优先级可以随着等待时间的增加而提高,因此长作业等待一段时间后仍能得到调度。
使用的公式:
完成时间 = 开始时间 + 需要运行时间
周转时间 = 完成时间 - 到达时间
带权周转时间 = 周转时间 / 需要运行时间
等待时间 = 当前时间 - 到达时间
优先权 = (等待时间 + 需要运行时间) / 需要运行时间
问题描述:
设计程序模拟进程的高响应比优先调度和时间片轮转RR调度过程。假设有n个进程分别在T1, … ,Tn时刻到达系统,它们需要的服务时间分别为S1, … ,Sn。如果选择RR算法,则需要指定时间片大小q,采用时间片轮转RR进程调度算法进行调度,如果选择高响应比优先调度算法,则可以直接调度,计算每个进程的完成时间,周转时间和带权周转时间,并且统计n个进程的平均周转时间和平均带权周转时间。
程序要求如下:
1)进程个数n;每个进程的到达时间T1, … ,Tn和服务时间S1, … ,Sn;如果选择时间片轮转法,则要输入时间片大小q。
2)要求高响应比优先和时间片轮转法RR调度进程运行,计算每个进程的周转时间,带权周转时间,并且计算所有进程的平均周转时间,带权平均周转时间;
3)输出:要求模拟整个调度过程,输出每个时刻的进程运行状态,如“时刻3:进程B开始运行”等等;
4)输出:要求输出计算出来的每个进程的周转时间,带权周转时间,所有进程的平均周转时间,带权平均周转时间。
【流程图】
【实验结果】
核心代码:
时间片轮转RR进程调度:
高响应比优先调度:
可读文本文件:
实验结果截图:
时间片轮转RR进程调度:
高响应比优先调度:
【源代码】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <iomanip>
#include <fstream>
using namespace std;
#define WAIT "Wait"//就绪状态
#define RUN "Run"//运行状态
#define FINISH "Finish"//完成状态
#define JOBNUMBER 5 //设置进程测试数为5
//存放每个进程信息的结构体
typedef struct{
char name;//进程名字
int ArrivalTime;//到达时间
int ServiceTime;//服务时间
int FinishedTime;//完成时间
int WholeTime;//周转时间
double WeightWholeTime;//带权周转时间
}RR;
static queue<RR>RRqueue; //用来模拟进程执行RR调度算法的队列
static double SumWT=0,SumWWT=0,AverageWT =0,AverageWWT=0;//平均周转时间、平均带权周转时间
static int q; //时间片数
static int n; //进程个数
static RR RRarray[100]; //进程结构体
static RR temp; //进程结构
void Enter();//输入时间片、到达时间、服务时间等
void RRfunction();//执行RR调度算法
void display();//显示各时间执行情况,以及各个时间值
//输入时间片、到达时间、服务时间等
void Enter(){
int i,j;
cout<<"Enter n: ";
cin>>n;
cout<<"Enter TimeSlice q: ";
cin>>q;
for (i=0;i<n;i++){
RRarray[i].name=i+65;//自动将进程名字顺序编号为A、B、C、D、E等
}
cout<<"Enter ArrivalTime: ";
for (i=0;i<n;i++){
cin>>RRarray[i].ArrivalTime;
}
cout<<"Enter ServiceTime: ";
for (i=0;i<n;i++){
cin>>RRarray[i].ServiceTime;
}
//根据达时间排序
for(i=0;i<n;i++) {
for(j=i+1;j<n;j++) {
if(RRarray[i].ArrivalTime > RRarray[j].ArrivalTime) {
temp = RRarray[i];
RRarray[i] = RRarray[j];
RRarray[j] = temp;
}
}
}
}
//执行RR调度算法
void RRfunction(){
char Moment[100]; //存储每个时间片p对应的进程名称
RRqueue.push(RRarray[0]); //第一个进程进队列
int MomentPoint = 0;
int CurrentTime=0;
int tempTime; //控制CurrentTime的累加时间,当前进程的服务时间小于时间片q的时候,起到重要作用
int i=1,j; //指向还未处理的进程的下标
int finalNumber = 0; //执行RR算法后,进程的个数
int Time[50];
bool canAdd=false;//用于解决CurrentTime在第一个进程完成计算时多加了一次服务时间的问题
//判断第一个进程的服务时间是否大于时间片,如果大于CurrentTime=q,如果小于CurrentTime=服务时间
if (RRarray[0].ServiceTime>=q)
CurrentTime = q;
else
CurrentTime = RRarray[0].ServiceTime;
while(!RRqueue.empty()){
for (j=i;j<n;j++){ //使得满足进程的到达时间小于当前时间的进程都进入队列
if (RRarray[j].name!=NULL && CurrentTime >= RRarray[j].ArrivalTime){
RRqueue.push(RRarray[j]);
i++;
}
}
if (RRqueue.front().ServiceTime<q)
tempTime = RRqueue.front().ServiceTime;
else
tempTime = q;
RRqueue.front().ServiceTime -= q; //进程每执行一次,就将其服务时间 -q
//将队首进程的名称放入数组中
Moment[MomentPoint] = RRqueue.front().name;
MomentPoint++;
Time[finalNumber] = tempTime;
finalNumber++;
if (RRqueue.front().ServiceTime <= 0) //把执行完的进程退出队列
RRqueue.pop(); //如果进程的服务时间小于等于,即该进程已经服务完了,将其退栈
else{
//将队首移到队尾
RRqueue.push(RRqueue.front());
RRqueue.pop();
}
if(canAdd){
CurrentTime += tempTime;
}
canAdd=true;
}
//进程输出处理 每个时间段对应的执行的进程
cout<<"各进程的执行时刻信息:"<<endl;
Time[finalNumber]=0;
int time = Time[0];
int count = 0;
int countTime=0;
for (i=0;i<finalNumber;i++)//计算完成时间
{
count = 0;
while(RRarray[count].name!=Moment[i] && count<n)
{
count++;
}
RRarray[count].FinishedTime = time;
if (i<finalNumber - 1)
{
time += Time[i+1];
}
}
for(i=0;i<finalNumber;i++){//输出
for(int j=0;j<Time[i];j++){
cout<<setw(3)<<countTime<<" --"<<setw(3)<<countTime+1<<setw(6)<<"时刻 "<<"进程"<<Moment[i]<<"执行";
for(int k=0;k<n;k++){
if(RRarray[k].ArrivalTime==countTime){
cout<<" 进程"<<RRarray[k].name<<"到达";
}
else if(RRarray[k].FinishedTime==countTime+1&&countTime!=0){
cout<<" 进程"<<RRarray[k].name<<"完成";
}
}
countTime+=1;
cout<<endl;
}
}
cout<<endl;
//周转时间、带权周转时间、平均周转时间、带权平均周转时间的计算
for (i=0;i<n;i++){
RRarray[i].WholeTime = RRarray[i].FinishedTime - RRarray[i].ArrivalTime;
RRarray[i].WeightWholeTime = (double)RRarray[i].WholeTime/RRarray[i].ServiceTime;
}
for (i=0;i<n;i++){
SumWT += RRarray[i].WholeTime;
SumWWT += RRarray[i].WeightWholeTime;
}
AverageWT = SumWT/n;
AverageWWT = SumWWT/n;
}
//显示各时间执行情况,以及各个时间值
void display(){
int i;
//输出各个时间
cout<<"ID"<<"\t";
cout<<"ArrivalTime"<<"\t";
cout<<"ServiceTime"<<"\t";
cout<<"FinishTime"<<"\t";
cout<<"WholeTime"<<"\t";
cout<<"WeightWholeTime"<<endl;
for (i=0;i<n;i++){
cout<<RRarray[i].name<<"\t\t";
cout<<RRarray[i].ArrivalTime<<"\t\t";
cout<<RRarray[i].ServiceTime<<"\t\t";
cout<<RRarray[i].FinishedTime<<"\t\t";
cout<<RRarray[i].WholeTime<<"\t\t";
cout<<setprecision(3)<<RRarray[i].WeightWholeTime<<"\t\t"<<endl;;
}
cout<<"SumWT = "<<setprecision(3)<<SumWT<<endl;
cout<<"SumWWT = "<<setprecision(3)<<SumWWT<<endl;
cout<<"AverageWT = "<<setprecision(3)<<AverageWT<<endl;
cout<<"AverageWWT = "<<setprecision(3)<<AverageWWT<<endl;
}
typedef struct JCB{
char jobName[10];//作业名
int arriveTime;//到达时间
int runTime;//需要运行时间
int startTime;//开始时间
int endTime;//完成时间
int turnoverTime;//周转时间
float useWeightTurnoverTime;//带权周转时间
char processStatus[10];//进程状态
};
static int currentTime = 0;//当前时间
static int finishNumber = 0;//进程完成数量
char JobArray[JOBNUMBER][10];//存放数组名信息的二元数组
float priority[JOBNUMBER];//存放进程优先级的一元数组
//创建JCB
void createJCB(struct JCB* jcb){
freopen("input.txt","r",stdin);
printf("从文件中读入三个参数的数据:\n");
printf("作业号 到达时间 需要运行时间\n");
for(int i = 0; i < 5; i++){
scanf("%s", &jcb[i].jobName);//作业号
scanf("%d", &jcb[i].arriveTime);//到达时间
scanf("%d", &jcb[i].runTime);//需要运行时间
jcb[i].startTime = 0;
jcb[i].endTime = 0;
jcb[i].turnoverTime = 0;
jcb[i].useWeightTurnoverTime = 0.0;
strcpy(jcb[i].processStatus, WAIT);
printf("%s\t%d\t%d\n",jcb[i].jobName, jcb[i].arriveTime,jcb[i].runTime);
}
printf("---------------------------------------------\n");
freopen("CON", "r", stdin);
}
//打印用途
void printJob(struct JCB* jcb){
printf("当前时间为%d\n", currentTime);
printf("作业号 到达时间 需要运行时间 开始时间 完成时间 周转时间 带权周转时间 进程状态\n");
for(int i = 0; i < JOBNUMBER; i++){
if(strcmp(jcb[i].processStatus, FINISH) == 0)//如果进程为finish状态,这样输出
printf("%s\t%d\t%4d\t\t%d\t%d\t %d\t %.2f\t %s\n", jcb[i].jobName, jcb[i].arriveTime, jcb[i].runTime, jcb[i].startTime, jcb[i].endTime, jcb[i].turnoverTime, jcb[i].useWeightTurnoverTime, jcb[i].processStatus);
else if(strcmp(jcb[i].processStatus, RUN) == 0)//如果进程为run状态,这样输出
printf("%s\t%d\t%4d\t\t%d\t运行中\t none\t none %s\n", jcb[i].jobName, jcb[i].arriveTime, jcb[i].runTime, jcb[i].startTime, jcb[i].processStatus);
else //如果进程为wait状态,这样输出
printf("%s\t%d\t%4d\t\t未运行\tnone\t none\t none %s\n", jcb[i].jobName, jcb[i].arriveTime, jcb[i].runTime, jcb[i].processStatus);
}
printf("---------------------------------------------\n");
}
//计算平均带权周转时间
float weightTurnoverTimeCount(struct JCB* jcb){
float sum = 0.0;
for(int i = 0; i < JOBNUMBER; i++)
sum += jcb[i].useWeightTurnoverTime;
return sum / JOBNUMBER;
}
//计算平均周转时间
float turnOverTimeCount(struct JCB* jcb){
float sum = 0.0;
for(int i = 0; i < JOBNUMBER; i++)
sum += jcb[i].turnoverTime;
return sum / JOBNUMBER;
}
//比较各个进程之间的到达时间,按升序排列
void compare(struct JCB* jcb){
for(int i = 0; i < JOBNUMBER; i++){
int min = jcb[i].arriveTime, minIndex = i;
for(int j = i + 1; j < JOBNUMBER; j++){
if(jcb[j].arriveTime < min){
min = jcb[j].arriveTime;
minIndex = j;
}
}
struct JCB temp = jcb[i];
jcb[i] = jcb[minIndex];
jcb[minIndex] = temp;
}
}
//打印进程调度顺序,平均周转时间及平均带权周转时间
void printInfo(struct JCB* jcb){
printf("1、进程调度顺序为:%s -> %s -> %s -> %s -> %s\n", JobArray[0], JobArray[1], JobArray[2], JobArray[3], JobArray[4]);
printf("2、平均周转时间为:%.2f\n",turnOverTimeCount(jcb));
printf("3、平均带权周转时间为:%.2f\n", weightTurnoverTimeCount(jcb));
printf("----------------------------------------------\n");
}
//两算法共同循环遍历部分
void loop(struct JCB* jcb, int i){
jcb[i].startTime = currentTime;
jcb[i].endTime = jcb[i].startTime + jcb[i].runTime;
jcb[i].turnoverTime = jcb[i].endTime - jcb[i].arriveTime;
jcb[i].useWeightTurnoverTime = jcb[i].turnoverTime * 1.0 / jcb[i].runTime;
strcpy(jcb[i].processStatus, RUN);
while(true){
if(currentTime == jcb[i].endTime){
strcpy(jcb[i].processStatus, FINISH);
finishNumber++;
if(finishNumber == JOBNUMBER)
printJob(jcb);
currentTime--;
break;
}
else{
printJob(jcb);
currentTime++;
}
}
}
//高响应比优先调度算法
void highestResponseRatioNext(struct JCB* jcb){
createJCB(jcb);
compare(jcb);
int i = 0, j = 0;
for(; finishNumber != JOBNUMBER; currentTime++){
float maxPriority = 0.0;
int indexPriority = 0;
if(currentTime < jcb[0].arriveTime)//当前时间小于第一个节点到来时间时,直接打印
printJob(jcb);
else{
for(int i = 0; i < JOBNUMBER; i++){
if(strcmp(jcb[i].processStatus, FINISH) != 0){
int waitTime = currentTime - jcb[i].arriveTime;
priority[i] = (waitTime + jcb[i].runTime) * 1.0 / jcb[i].runTime;
if(priority[i] > maxPriority){
maxPriority = priority[i];
indexPriority = i;
}
}
}
strcpy(JobArray[j++], jcb[indexPriority].jobName);
loop(jcb, indexPriority);
}
}
printInfo(jcb);//打印进程调度顺序,平均周转时间及平均带权周转时间
currentTime = 0;//当前时间置位
finishNumber = 0;//完成进程数量置位
}
//菜单函数
void menu(struct JCB* jcb){
int input;
while(true){
printf("----------------------------------------------\n");
printf("| 1、时间片轮转RR进程调度算法 |\n");
printf("| 2、响应比高者优先调度算法 |\n");
printf("| 3、退出 |\n");
printf("----------------------------------------------\n");
printf("请输入序号以继续程序:");
scanf("%d", &input);
switch(input){
case 1: Enter();
RRfunction();
display();
break;
case 2:highestResponseRatioNext(jcb);
break;
case 3:
exit(0);
default:printf("输入有误,请重新输入!!!\n");
break;
}
}
}
//主函数
int main(){
struct JCB jcb[JOBNUMBER];
menu(jcb);
system("pause");
return 0;
}
参考网址:https://blog.csdn.net/qq_40695551/article/details/84932694
https://blog.csdn.net/remoa_dengqinyi/article/details/52961771