实验二、作业调度模拟实验
物联网工程 张怡 201306104149
一、实验目的
(1)加深对作业调度算法的理解;
(2)进行程序设计的训练。
二、实验内容和要求
1.至少用三种调度算法:
1) 采用先来先服务(FCFS)调度算法,即按作业到达的先后次序进行调度。总是首先调度在系统中等待时间最长的作业。
2) 短作业优先 (SJF) 调度算法,优先调度要求运行时间最短的作业。
3) 响应比高者优先(HRRN)调度算法,为每个作业设置一个优先权(响应比),调度之前先计算各作业的优先权,优先数高者优先调度。RP (响应比)= 作业周转时间 / 作业运行时间=1+作业等待时间/作业运行时间
每个作业由一个作业控制块JCB表示,JCB可以包含以下信息:作业名、提交(到达)时间、所需的运行时间、所需的资源、作业状态、链指针等等。
作业的状态可以是等待W(Wait)、运行R(Run)和完成F(Finish)三种之一。每个作业的最初状态都是等待W。
2. 模拟数据的生成
1) 允许用户指定作业的个数(2-24)。
2) 允许用户选择输入每个作业的到达时间和所需运行时间。
3)允许用户选择通过伪随机数指定每个作业的到达时间(0-30)和所需运行时间(1-8)。
3. 模拟程序的功能
1) 按照模拟数据的到达时间和所需运行时间,执行FCFS, SJF和HRRN调度算法,程序计算各作业的开始执行时间,各作业的完成时间,周转时间和带权周转时间(周转系数)。
2) 动态演示每调度一次,更新现在系统时刻,处于运行状态和等待各作业的相应信息(作业名、到达时间、所需的运行时间等)对于HRRN算法,能在每次调度时显示各作业的响应比R情况。
三、实验方法、步骤及结果测试
1. 源程序名:压缩包文件(rar或zip)中源程序名ZuoYeDiaoDu.c
可执行程序名:ZuoYeDiaoDu.exe
2. 原理分析及流程图
这个程序主要是对三种作业调度算法的使用,主程序里是两个界面菜单和调度算法程序的调用。menu1是初始界面,提示是进入“用户输入数据模式”、“随机数制定数据模式”,还是要退出程序。若选择1,则提示“请输入作业个数(2~24):”,输入作业个数后提示输入“作业名称提交时刻运行时间”,输入完毕后打印用户刚输入的原始数据,并提示四个选项,用户可选择任意一项,若输入1~3之中的任意一个,则进入该数字对应的作业调度算法,若输入4则返回初始界面。
进入作业调度算法后,提示按Enter键继续作业,并打印“当前时间”、“还未进入后备队列的作业”、“进入后备队列的作业”以及“处于运行的作业”。最后打印“已经完成的作业”,按Enter键打印“平均周转时间”和“平均周转系数”,并提示四个选项,用户可选择1~3继续进行作业调度,或者选择4返回初始界面。
3. 主要程序段及其解释:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MAX 24
typedef struct job
{
char jname[10];//作业名
int arrivetime;//提交时间
int actiontime;//执行时间
int stime;//开始时间
int etime;//完成时间
int zztime;//周转时间
float zzxs;//周转系数
}JOB;
JOB job[MAX],HBjob[MAX];
JOB temp;
float ave_zztime=0,ave_zzxs=0; //平均周转时间和周转系数
int num=5;
void input()
{ int i=0;
system("cls");//清屏 , system()函数是调用dos命令. cls是dos命令中的清屏命令clear screen的简写
printf("请输入作业个数(2-24):");
scanf("%d",&num);
while(num<2&&num>24)
{ printf(" 请重新输入作业个数(2~24):");
scanf("%d",&num);
}
for(i=0;i<num;i++)
{ printf(" 请输入第%d个数作业的名称:",i+1);
scanf("%s",job[i].jname);
printf(" 请输入第%d个作业的提交时刻:",i+1);
scanf("%d",&job[i].arrivetime);
printf(" 请输入第%d个作业的运行时间:",i+1);
scanf("%d",&job[i].actiontime);
}
system("cls");
printf(" 用户输入的原始数据 ");
printf(" 作业名称 提交时刻 运行时间 ");
for(i=0;i<num;i++)
{ printf(" %s %d %d",job[i].jname,job[i].arrivetime,job[i].actiontime);
printf(" ");
}
}
void paixu()
{
int i,j;
for(i=1;i<num;i++)
{
for(j=0;j<num-i;j++)
{
if(job[j].arrivetime>job[j+1].arrivetime)
{
temp=job[j];
job[j]=job[j+1];
job[j+1]=temp;
}
}
}
printf("按提交时间排序后,还未进入后备队列的任务! ");
printf("作业名称 提交时刻 运行时间 ");
for(i=0;i<num;i++)
{
printf(" %s %d %d",job[i].jname,job[i].arrivetime,job[i].actiontime);
printf(" ");
}
}
void jisuan()
{
int i;
for(i=0;i<num;i++)
{
if(i==0)
{
job[i].stime=job[i].arrivetime;
job[i].etime=job[i].arrivetime+job[i].actiontime;
}
else if(job[i-1].etime<=job[i].arrivetime)//上一作业的完成时间<=本次作业的提交时间
{
job[i].stime=job[i].arrivetime;
job[i].etime=job[i].arrivetime+job[i].actiontime;
}
else
{
job[i].stime=job[i-1].etime;
job[i].etime=job[i].stime+job[i].actiontime;
}
}
for(i=0;i<=num;i++)
{
job[i].zztime=job[i].etime-job[i].arrivetime;//周转时间=完成时间-提交时间
job[i].zzxs=(float)job[i].zztime/job[i].actiontime;//周转系数=周转时间/执行时间
}
}
void FCFS()
{
int i,j,k,l,time=0;
printf(" 按先来先服务优先调度算法进行调度! ");
paixu();
jisuan();
i=0;
while(1)
{
if(i==num)
{
for(l=0;l<num;l++)
{
ave_zztime+=job[l].zztime;
}
ave_zztime=ave_zztime/num; //平均周转时间=周转时间总和/作业个数
for(l=0;l<num;l++)
{
ave_zzxs+=job[l].zzxs;
}
ave_zzxs/=num;
printf("平均周转时间为:%.2f",ave_zztime);
printf(" 平均周转系数为:%.2f ",ave_zzxs);
break;
break;
}
printf(" 当前系统时间为:%d ",time);
if(time>=job[i].arrivetime)
{
printf("还未进入后备队列的作业! ");
printf("作业名称 提交时刻 运行时间 ");
for(j=0;j<num;j++)
{
if(time<job[j].arrivetime)
{
printf(" %s %d %d ",job[j].jname,job[j].arrivetime,job[j].actiontime);
}
}
if(time<job[num-1].arrivetime)
{ printf(" 进入后备队列的作业! ");
printf("作业名称 提交时刻 运行时间 ");
for(k=num-1;k>=i;k--)
{
if(time>=job[k].arrivetime)
{ printf(" %s %d %d ",job[k].jname,job[k].arrivetime,job[k].actiontime);
}
}
}
printf(" 处于运行的作业为:%s ",job[i].jname);
printf("已经完成的作业! ");
printf("作业名称 提交时刻 运行时间 开始时刻 完成时刻 周转时间 周转系数 ");
for(k=0;k<=i;k++)
{
printf("%5s %3d %3d %3d %3d %3d %.2f ",job[k].jname,job[k].arrivetime,job[k].actiontime,job[k].stime,job[k].etime,job[k].zztime,job[k].zzxs);
}
time=time+job[i].actiontime;
i++;
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
}
else
{
time++;
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
}
}
}
void SJF()
{
int i,j,k,l=0,time=0;
paixu();
printf("按短作业优先调度算法进行调度! ");
i=0;
while(1)
{
if(i==num)
{
for(l=0;l<num;l++)
{
ave_zztime+=job[l].zztime;
}
ave_zztime/=num;
for(l=0;l<num;l++)
{
ave_zzxs+=job[l].zzxs;
}
ave_zzxs/=num;
printf("平均周转时间为:%.2f",ave_zztime);
printf(" 平均周转系数为:%.2f ",ave_zzxs);
break;
}
printf(" 当前系统时间为:%d ",time);
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
if(time>=job[i].arrivetime)
{
printf("还未进入后备队列的作业! ");
printf("作业名称 提交时刻 运行时间 ");
for(j=i;j<num;j++)
{
if(time<job[j].arrivetime)
{
printf(" %s %d %d ",job[j].jname,job[j].arrivetime,job[j].actiontime);
}
}
for(j=i;j<num-1;j++)
{
for(k=i;k<num-1;k++)
{
if((job[k].actiontime>job[k+1].actiontime)&& (time>=job[k].arrivetime)&& (time>=job[k+1].arrivetime))
{
temp=job[k];
job[k]=job[k+1];
job[k+1]=temp;
}
}
}
printf(" 进入后备队列的作业! ");
printf("作业名称 提交时刻 运行时间 ");
for(k=i;k<num;k++)
{
if(time>=job[k].arrivetime)
{
printf(" %s %d %d ",job[k].jname,job[k].arrivetime,job[k].actiontime);
}
}
jisuan();
printf(" 处于运行的作业为:%s ",job[i].jname);
printf("已经完成的作业! ");
printf("作业名称 提交时刻 运行时间 开始时刻 完成时刻 周转时间 周转系数 ");
for(k=0;k<=i;k++)
{
printf("%5s %3d %3d %3d %3d %3d %.2f ",job[k].jname,job[k].arrivetime,job[k].actiontime,job[k].stime,job[k].etime,job[k].zztime,job[k].zzxs);
}
time=time+job[i].actiontime;
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
i++;
}
else
{
time++;
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
}
}
}
void HRRF()
{
int i,j,k,l=0,time=0;
float max=0;
printf(" 按响应比优先调度算法进行调度! ");
paixu();
i=0;
while(1)
{
if(i==num)
{
for(l=0;l<num;l++)
{
ave_zztime+=job[l].zztime;
}
ave_zztime/=num;
for(l=0;l<num;l++)
{
ave_zzxs+=job[l].zzxs;
}
ave_zzxs/=num;
printf("平均周转时间为:%.2f",ave_zztime);
printf(" 平均周转系数为:%.2f ",ave_zzxs);
break;
break;
}
printf(" 当前系统时间为:%d ",time);
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
if(time>=job[i].arrivetime)
{
printf("还未进入后备队列的作业! ");
printf("作业名称 提交时刻 运行时间 ");
for(j=i;j<num;j++)
{
if(time<job[j].arrivetime)
{
printf(" %s %d %d ",job[j].jname,job[j].arrivetime,job[j].actiontime);
}
}
if(i==0)
{
jisuan();
}
else{
jisuan();
for(j=i;j<num-1;j++)
{
for(k=i;k<num-1;k++)
{
max=(float)(job[k-1].etime-job[k].arrivetime+job[k].actiontime)/job[k].actiontime;
if(max<(float)(job[k].etime-job[k+1].arrivetime+job[k+1].actiontime)/job[k+1].actiontime && (time>=job[k].arrivetime)&&(time>=job[k+1].arrivetime))
{
temp=job[k];
job[k]=job[k+1];
job[k+1]=temp;
}
}
}
}
printf(" 进入后备队列的作业! ");
printf("作业名称 提交时刻 运行时间 ");
for(k=i;k<num;k++)
{
if(time>=job[k].arrivetime){
printf(" %s %d %d ",job[k].jname,job[k].arrivetime,job[k].actiontime);
}
}
printf(" 处于运行的作业为:%s ",job[i].jname);
printf("已经完成的作业! ");
printf("作业名称 提交时刻 运行时间 开始时刻 完成时刻 周转时间 周转系数 ");
for(k=0;k<=i;k++)
{
printf("%5s %3d %3d %3d %3d %3d %.2f ",job[k].jname,job[k].arrivetime,job[k].actiontime,job[k].stime,job[k].etime,job[k].zztime,job[k].zzxs);
}
time=time+job[i].actiontime;
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
i++;
}
else
{ time++;
printf(" 请按Enter键继续...");
fflush(stdin);
getchar();
}
}
}
int menu2()
{ int chioce;
printf(" 1.先来先服务(FCFS)调度算法 ");
printf(" 2.短作业优先(SJF) 调度算法 ");
printf(" 3.响应比优先(HRRF)调度算法 ");
printf(" 4.返回上一层 ");
printf(" 请选择:");
scanf("%d",&chioce);
return chioce;
}
void suiji()
{
int i=0,j=0;
system("cls");
printf("请输入作业个数(2-24):");
scanf("%d",&num);
while(num<2&&num>24)
{ printf(" 请重新输入作业个数(2~24):");
scanf("%d",&num);
}
for(i=0;i<num;i++)
{ itoa(i+1,job[i].jname,10);
job[i].arrivetime=rand()%10+1;
job[i].actiontime=rand()%10+1;
}
system("cls");
printf(" 用户输入的原始数据 ");
printf(" 作业名称 提交时刻 运行时间 ");
for(i=0;i<num;i++)
{ printf(" %s %d %d",job[i].jname,job[i].arrivetime,job[i].actiontime);
printf(" ");
}
}
int menu1()
{
int choice;
do{
printf(" --------------------------------------------------------- ");
printf(" 1.用户输入数据模式 ");
printf(" 2.随机数指定数据模式 ");
printf(" 3.退出 ");
printf(" --------------------------------------------------------- ");
printf(" 请选择: ");
scanf("%d",&choice);
getchar();
if(choice<0||choice>3)
{ printf("输入有错!!!请重新选择!");
scanf("%d",&choice);
getchar();
}
}while(choice<0||choice>3);
return choice;
}
main()
{ int chioce1=0,chioce2=0;
while(1)
{FH: system("cls");//清屏
chioce1=menu1();
switch(chioce1)
{
case 1:
{
input();
break;
}
case 2:
{
suiji();
break;
}
case 3:
{
printf(" 谢谢使用!!! ");
exit(0);//正常运行程序并退出程序;
}
}
while(1){
chioce2=menu2();
switch(chioce2){
case 1:
{
FCFS();//先来先服务
break;
}
case 2:
{
SJF();//短作业优先
break;
}
case 3:
{
HRRF();//响应比优先
break;
}
case 4:
{
goto FH;//回到开始界面
}
}
}
}
}
4. 运行结果及分析
运行程序,有如下效果:显示菜单选项并提示“请选择:”。输入“1”跳入“用户输入数据模式”,输入“2”跳入“随机数指定数据模式”。输入“3”则退出该程序。 “随机数指定数据模式”只需输入作业个数,其他数据由随机数组成。
“用户输入数据模式”需要用户自己输入数据,可选择要输入的数据组数(2~24)。
随后提示输入“作业名称 提交时刻 运行时间”,输入完毕后显示输入的数据。此时可选择调度算法,输入“1”则进行先来先服务调度,输入“2”进行短作业优先调度,输入“3”进行响应比优先调度,输入“4”则返回上一层。提示“请选择:”。
输入选项后显示如下:(按“Enter”键继续进行调度)
调度过程中打印已完成的作业和等待中的作业,完成后打印各组作业的“作业名称 提交时刻 运行时间 开始时刻 完成时刻 周转时间 周转系数”。 作业调度完成后可选择下图四个选项中的其中一个,使程序继续进行作业调度或者返回到初始页面。
四、实验总结
这次的实验主要是看我们对作业调度算法的熟悉程度,开始的时候对算法不够了解,因此进度很慢,经过上网查资料问同学后加深了对算法的了解。先做了个程序框架,将需要用到的算法公式和要用到的参数列出来,将然后写成代码。为了使页面美观,初始界面输入选项后和跳回初始界面时进行清屏操作。此外,每次完成输入后都会把用户输入原始数据一起打印出来,调动完成后也会按照先后顺序把已完成的作业信息一起打印出来,方便观察。最后计算出“平均周转时间”和“平均周转系数”并打印出来,然后提示四个选项,用户可选择继续进行作业调度或返回到初始界面。