一、实验内容
1.编程实现处理机调度算法,算法包括:时间片轮转法,短进程优先算法,动态优先级算法。
2.可选择进程数量,即进程数目可动态变化。
3.主程序包括三种算法,执行时在主界面选择算法(可用函数实现),进入子页面后输入进程数(运行时间,优先数由随机函数产生),执行,显示结果。
二、算法思想
1.时间片轮转调度算法
算法思想:系统把所有的就绪进程按FCFS原则排成一个队列,
且规定一个时间片作为进程每次使用处理机的最长时间单位,
按时间片把处理机轮流分配给当前位于就绪队列队首的进程使用,当该进程的时间片用完以后,系统产生时钟中断,剥夺该进程的执行,将它送到就绪队列队尾,等待下一轮次的调度。同时处理机调度程序又去调度当前就绪队列的队首进程,也让它运行给定的时间片,如此循环往复。
2.最短进程调度算法
算法思想:根据进程的运行时间,确定进程的优先级,进程的运行时间越短,就越先被执行
3.动态优先数算法
可抢占方式的调度算法
若所有的进程具有相同的优先权初值,则按照FCFS算法,最先进入就绪队列的进程最先获得处理机。若所有的就绪进程具有各不相同的优先权初值,对于优先权初值低的进程,在等待足够的时间后,其优先权可能升为最高,从而获得处理机执行。
基本原则
(1)根据进程占有CPU时间多少来决定,当进程占有CPU时间愈长,那么,在它被阻塞之后再次获得调度的优先级就越低,反之,进程获得调度的可能性越大;
(2)根据进程等待CPU时间多少来决定,当进程在就绪队列中等待时间愈长,那么,在它被阻塞之后再次获得调度的优先级就越高,反之,进程获得调度的可能性越小。
三、实验代码
#include <iostream>
#include <cstring>
#include <queue>
#include <stdio.h>
#include <algorithm>
using namespace std;
/********************1-时间片轮转法*********************************/
struct PCB1
{
int name; //定义进程号
int arrivalTime; // 到达时间
int excutionTime; //运行时间
int restTime; //剩余时间
int state=0; //进程的当前状态
//运行1,就绪0,完成2 初始都是就绪状态
//函数重载
bool operator<(const PCB1 &obj) const
{
return arrivalTime < obj.arrivalTime;
}
};
queue<PCB1> q; //就绪队列
PCB1 P1[100];
bool isStart = false; //是否开始执行
void createP1(int proNum)
{
//生成proNum个进程,并将进程加入队列当中
for(int i=1;i<=proNum;i++)
{
PCB1 process;
process.name = i;
process.arrivalTime = rand()%20; //生成1-20以内的随机整数
process.excutionTime = rand()%100+20; //运行时间20-120以内
process.restTime = process.excutionTime; //剩余时间
P1[i] = process;
}
}
void displayP1()
{
//展示时间片轮转调度算法下的进程的运行情况
queue<PCB1> q2;
q2 = q;//当前队列的复制品
if(isStart) //开始执行
printf("\n**********************程序开始运行**********************\n");
else
printf("\n**********************进程初始情况**********************\n");
printf("进程号 到达时间/s 运行时间/s 剩余时间/s 当前状态\n");
while (!q2.empty())
{
PCB1 currentP = q2.front();
string state;
q2.pop();
if(currentP.state==0)
state = "就绪状态";
else if(currentP.state==1)
state = "运行状态";
else if(currentP.state==2)
state = "完成状态";
printf("%6d%8d%8d%14d%",currentP.name,currentP.arrivalTime,currentP.excutionTime,currentP.restTime);
cout << " "<< state << endl;
}
}
//时间片轮转法调度算法
void RR(int proNum)
{
//1-根据进程数创建进程的队列
createP1(proNum);
//2-根据进程的到达时间排序
sort(P1+1, P1+proNum+1);
//3-遍历进程数组,创建就绪队列
for(int i=1;i<=proNum;i++)
q.push(P1[i]);
//4-打印初始状态
displayP1();
//5-执行进程
isStart = true; //开始执行进程,表示置为true
int timeSlice=30; //这里指定时间片为30秒
cout << "时间片定义为30秒" << endl;
while(!q.empty()) //就绪队列不为空,执行循环
{
q.front().state = 1; //执行就绪队列队首的进程
displayP1(); //展示进程的执行情况
PCB1 currentPro = q.front();
currentPro.restTime -= 30; //进程的剩余时间减少30秒
q.pop(); //该进程出队
if(currentPro.restTime <= 0) //在该时间片中当前进程执行完毕
{
currentPro.state = 2; //执行完毕状态
continue;
}
else
{
currentPro.state = 0; //重新处于就绪状态
q.push(currentPro); //重新加入队列
}
}
cout << "就绪队列为空,进程执行完毕!!\n" << endl;
}
/********************2-短进程优先算法*********************************/
struct PCB2
{
int name; //定义进程号
int arrivalTime; // 到达时间
int excutionTime; //运行时间
int startTime; //开始执行时间
int finishTime; //完成时间
int TurnaroundTime; //周转时间
//函数重载
bool operator<(const PCB2 &obj) const
{
return excutionTime < obj.excutionTime;
}
};
PCB2 P2[100];
bool isStart2 = false;
void createP2(int proNum)
{
//创建进程
for(int i=1;i<=proNum;i++)
{
PCB2 process;
process.name = i;
process.arrivalTime = rand()%20; //生成1-20以内的随机整数
process.excutionTime = rand()%100+20; //运行时间20-120以内
P2[i] = process;
}
}
void displayP2(int proNum)
{
//展示短进程优先调度算法下的进程的运行情况
if(isStart2==false)
{
printf("\n******************进程初始状态*****************\n");
printf("进程号 到达时间/s 运行时间/s \n");
for(int i=1;i<=proNum;i++)
{
printf("%6d%8d%8d\n",P2[i].name,P2[i].arrivalTime,P2[i].excutionTime);
}
printf("***********************************************\n");
cout << "进程执行顺序如下:\n" << endl;
int i;
for(i=1;i<proNum;i++)
{
cout << P2[i].name << "-->";
}
cout << P2[i].name << endl;
}
else
{
printf("\n****************************进程运行情况*****************************\n");
printf("进程号 到达时间/s 运行时间/s 开始执行时间/s 完成时间/s 周转时间/s\n");
for(int i=1;i<=proNum;i++)
{
printf("%6d%8d%8d%16d%14d%10d\n",P2[i].name,P2[i].arrivalTime,P2[i].excutionTime,P2[i].startTime, P2[i].finishTime,P2[i].TurnaroundTime);
}
printf("*********************************************************************\n");
}
}
void SPF(int proNum)
{
//1-根据进程数创建进程
createP2(proNum);
//2-根据进程执行时间进行排序
sort(P2+1, P2+proNum+1);
//3-展示根据进程长短排序后的进程的情况,以及进程运行情况
displayP2(proNum);
//4-执行调度
isStart2 = true;
int T=P2[1].arrivalTime;
for(int i=1;i<=proNum;i++)
{
//上一个进程的结束时间就是,下一个进程的开始时间
P2[i].startTime=T;
T += P2[i].excutionTime;
P2[i].finishTime = T;
P2[i].TurnaroundTime = P2[i].finishTime - P2[i].arrivalTime;//周转时间
}
//5-展示进程执行的情况
displayP2(proNum);
}
/********************3-动态优先级算法*********************************/
struct PCB3
{
int name; //定义进程号
int arrivalTime; //进程到达的时间
int excutionTime; //运行时间
int restTime; //剩余完成时间
int priority; //优先数
int state=0; //进程的状态,未到达0 就绪1,执行2,完成3
//函数重载
bool operator<(const PCB3 &obj) const
{
return priority > obj.priority; //优先数从高到低排序
}
};
PCB3 P3[100];
bool isStart3=false; //是否开始调度
int earlistTime=0x3f3f3f; //最早到达的进程·
int totalTime=0;
priority_queue<PCB3> que; //就绪 优先队列
queue<PCB3> finishedQue; //已完成进程队列
queue<PCB3> initQue; //未到达进程队列
void createP3(int proNum)
{
for(int i=1;i<=proNum;i++)
{
PCB3 process;
process.name = i;
process.arrivalTime = rand()%5+1; //到达时间在5以内
process.excutionTime = rand()%5+1; //运行时间在5以内
process.priority = rand()%10; //优先数
process.restTime = process.excutionTime;
P3[i] = process;
if(process.arrivalTime < earlistTime)
earlistTime = process.arrivalTime;
totalTime += process.excutionTime;
}
}
void displayP3(int proNum)
{
if(!isStart3)
{
printf("\n******************进程初始状态*****************\n");
printf("进程号 到达时间/s 运行时间/s 优先数 状态\n");
for(int i=1;i<=proNum;i++)
{
printf("%6d%8d%8d%12d%10d\n",P3[i].name,P3[i].arrivalTime,P3[i].excutionTime,P3[i].priority,P3[i].state);
}
printf("***********************************************\n");
}
}
void displayQue(queue<PCB3> q)
{
while(!q.empty())
{
PCB3 currentProcess = q.front();
q.pop();
printf("%6d%8d%8d%12d%10d\n",currentProcess.name,currentProcess.arrivalTime,currentProcess.excutionTime,currentProcess.priority,currentProcess.state);
}
}
void displayQue(priority_queue<PCB3> q)
{
while(!q.empty())
{
PCB3 currentProcess = q.top();
q.pop();
printf("%6d%8d%8d%12d%10d\n",currentProcess.name,currentProcess.arrivalTime,currentProcess.excutionTime,currentProcess.priority,currentProcess.state);
}
}
bool cmp(PCB3 a, PCB3 b)
{
return a.arrivalTime < b.arrivalTime;
}
//优先数是动态变化的,每次取优先级最高的那个进程,等待时间增加,处于就绪状态的进程的优先数增加
//将处理机的调度权限分配给优先数较高的进程
//进行抢占式调度
//以时间为主线
//执行时间越长,优先数会下降
//优先数相同时,根据到达时间,先来先服务
//就绪队列中优先级最高的进程
//这个进程必须是已经到达的
//给已经到达并处于等待状态的进程的优先数+1
//给正在运行的进程优先数-1
//创建一个就绪队列,这个就绪队列是优先队列,进程数高的是靠前的
//从到达时间最早的那个进程开始,设为开始时间,这个进程先入队
void DP(int proNum)
{
//1-创建进程
createP3(proNum);
//2-根据到达时间排个顺序
sort(P3+1, P3+proNum+1,cmp);
//3-展示进程的初始情况
cout << "状态说明:" << endl;
cout << "0:未到达, 1:就绪状态,2:运行状态,3:完成状态" << endl;
displayP3(proNum);
//将进程加入一个队列(代表未执行进程)该队列包含所有的未执行进程
for(int i=1;i<=proNum;i++)
{
initQue.push(P3[i]); //加入队列
}
//4-进行调度
isStart3 = true;
cout << "最早开始时间为:第" << earlistTime << "秒" << endl;
cout << "完成时间为:第" << earlistTime+totalTime << "秒" << endl;
for(int t=earlistTime; t<=(earlistTime+totalTime);t++)
{
cout << "当前时间为:第" << t << "秒!" << endl;
//4-1 判断未执行进程队列队首进程是否可以处于就绪状态
if(!initQue.empty() && initQue.front().arrivalTime==t)
{
initQue.front().state=1; //就绪状态
que.push(initQue.front()); //加入就绪队列
initQue.pop(); //出队
}
//4-2 每秒钟要进行一次所有进程状态的展示
printf("****************************进程运行情况*****************************\n");
printf("进程号 到达时间/s 运行时间/s 优先数 状态\n");
//4-2-1 展示initQue中剩余进程的状态(未执行进程)
if(!initQue.empty())
displayQue(initQue);
//4-3 若就绪队列不为空,从就绪队列中取出当前优先数最高进程,让它处于执行状态
PCB3 runProcess;
if(!que.empty())
{
runProcess = que.top(); //就绪队列为优先队列
que.pop();//出队
runProcess.state = 2; //处于运行状态
runProcess.priority--;//优先数减1
runProcess.restTime--; //剩余完成时间减1
//4-2-2 展示正在执行的进程的情况(正在执行进程)
printf("%6d%8d%8d%12d%10d\n",runProcess.name,runProcess.arrivalTime,
runProcess.excutionTime,runProcess.priority,runProcess.state);
}
else
{
runProcess.name = 0;
}
//4-4 遍历就绪队列中的其他每一个进程,将它们的优先数加1
PCB3 process;
priority_queue<PCB3> temporaryQue; //临时的优先队列
while(!que.empty())
{
process = que.top(); //获取最顶的元素
process.priority += 1; //优先数加1
temporaryQue.push(process);
que.pop();
}
que = temporaryQue; //重新赋值给que
//4-2-3 展示就绪队列中所有进程信息 (就绪进程)
if(!que.empty())
displayQue(que);
//4-2-4 展示完成队列中所有的进程信息(完成进程)
if(!finishedQue.empty())
displayQue(finishedQue);
//4-5 判断正在运行的进程在这一秒后否运行完毕,如果运行完毕,置状态为3,加入完成队列,
//如果没有运行完毕,置状态为1,加入就绪队列
if(runProcess.name == 0)
{
//说明原来的就绪队列是空的
cout << "就绪队列为空\n" << endl;
}
else
{
if(runProcess.restTime==0)
{
runProcess.state = 3;
finishedQue.push(runProcess);
}
else
{
runProcess.state = 1;
que.push(runProcess);
}
}
}
printf("进程调度完毕!");
}
//调度程序
void dispatch()
{
/*
函数名称:调度算法模拟函数
*/
int proNum; //进程的数量
int choice; //功能选择
char isContinue; //是否继续
do{
printf(" ** 输入 1-时间片轮转法 *\n");
printf(" ** 输入 2-短进程优先算法 *\n");
printf(" ** 输入 3-动态优先级算法 *\n");
printf(" ** 输入 0-退出该程序 *\n");
printf("\n提示:请根据自己的需求选择相应的操作数:\n");
cin >> choice ;
/*提示输入字母,用switch语句存入到case中*/
switch(choice)
{
case 0:
break;
case 1:
printf("您选择的是时间片轮转法\n\n");
printf("请输入进程的数量:\n");
cin >> proNum;
RR(proNum);
break;
case 2:
printf("\n您选择的是短进程优先算法\n\n");
printf("请输入进程的数量:\n");
cin >> proNum;
SPF(proNum);
break;
case 3:
printf("\n您选择的是动态优先级调度算法\n\n");
printf("请输入进程的数量:\n");
cin >> proNum;
DP(proNum);
break;
default:
printf("\n你的输入有误,请确定是从0到3之间进行输入,O(∩_∩)O谢谢\n");
break;
}
printf("\n是否继续操作(y/n) ?");
fflush(stdin);
isContinue=getchar();
}while(isContinue=='y'||isContinue=='Y');
}
int main()
{
printf("\t\t* 调度算法模拟 *\n");
dispatch();
return 0;
}