可变时间片轮转+先来先服务实验报告.docx
《可变时间片轮转+先来先服务实验报告.docx》由会员分享,可在线阅读,更多相关《可变时间片轮转+先来先服务实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
可变时间片轮转+先来先服务实验报告
目的要求:
用高级语言编写一个程序,先用可变时间片轮转法将输入的任意个进程进行调度,再用先来先服务法对它们进行作业调度,以加深对进程调度和作业调度算法的理解。
数据结构设计:
进程属性结构:
structPCBNode
{intPID;//进程ID
intpriority;//优先数
intTrTime;//总运行时间
intRTime;//剩余运行时间
intATime;//从开始到全部进入就绪队列所需的时间
intSTime;//开始运行时间
intFTime;//完成运行时间
inttTime;//周转时间
floatWtTime;//带权周转时间
};
队列属性结构:
structQNode//进程队列
{intID;
structQNode*next;//队列中下一个进程指针
};
队列头结构:
structLQ
{QNode*head;//队列首部
};
进程输入类:
voidinput(PCBNode*PT,intPN);
进程初始化类:
voidInitialQueue(LQ&Q,PCBNode*PT,intPN);
时间片轮转类
voidRoundRobin(LQ&Q,intpiece,int&tTimeSum,int&WtTimeSum,PCBNode*PT);
时间片分配类:
boolDeal(LQ&Q,QNode*q,QNode*p,intpiece,int&CTime,PCBNode*PT);
先来先服务类:
voidFCFS(LQ&Q,int&tTimeSum,int&WtTimeSum,PCBNode*PT);
实验环境:
C++语言程序设计平台
算法流程设计:
运行事例演示:
input文本中输入:
运行结果:
在input文本中所输入的三列数据分别为:
各进程的从开始到全部进入就绪队列所需的时间、剩余运行时间、优先数,而真正在轮转与服务中起到作用的只有前两者。
上述程序0到4的编号是按每行进程的输入顺序分配的,在时间片轮转调度中,其执行顺序起初也按编号的从小到大排序,但当它们由于一次使用完时间片后为完成其所有工作量而需再次被调用时,其运行顺序就与input文本中第一列数据相关了,例如进程2和3,由于进程3全部进入队列的时间为11,而当进程2第一次运行后所过去的时间只有9(执行了三次大小为3的时间片),于是接下来仍运行一次进程2,之后才轮到进程3(此时过去时间为12),接着就是剩余进程轮转运行直到结束。
其后就是先来先服务,按进程编号由小到大运行,各个进程所占的时刻数就是它们input文本中第二列的数据,也就是运行时间。
源程序:
#include
#include
#include
#include
usingnamespacestd;
structPCBNode
{intPID;//进程ID
intpriority;//优先数
intTrTime;//总运行时间
intRTime;//剩余运行时间
intATime;//从开始到全部进入就绪队列所需的时间
intSTime;//开始运行时间
intFTime;//完成运行时间
inttTime;//周转时间
floatWtTime;//带权周转时间
};
structQNode//进程队列
{intID;
structQNode*next;//队列中下一个进程指针
};
structLQ
{QNode*head;//队列首部
};
voidinput(PCBNode*PT,intPN);
voidInitialQueue(LQ&Q,PCBNode*PT,intPN);
voidRoundRobin(LQ&Q,intpiece,int&tTimeSum,int&WtTimeSum,PCBNode*PT);
boolDeal(LQ&Q,QNode*q,QNode*p,intpiece,int&CTime,PCBNode*PT);
voidFCFS(LQ&Q,int&tTimeSum,int&WtTimeSum,PCBNode*PT);
intmain()
{LQQ;//就绪队列
Q.head=NULL;
intPN;//进程数
intpiece;//时间片大小
inttTimeSum=0;//周转时间
intWtTimeSum=0;//带权周转时间
PCBNode*PT=newPCBNode[PN];//进程表
cout<<"请输入进程数:
";
cin>>PN;//输入在input文件中所输入的进程的个数(每行一个进程)
cout<<"请输入时间片大小:
";
cin>>piece;//输入所需时间片的大小
input(PT,PN);//调用input.txt文件中进程数据
InitialQueue(Q,PT,PN);//初始化就绪队列
RoundRobin(Q,piece,tTimeSum,WtTimeSum,PT);//可变时间片轮转进程调度,调用Deal(),piece为时间片大小
cout<<"可变时间片轮的平均周转时间为:
"<cout<<"可变时间片轮的平均带权周转时间为:
"<input(PT,PN);
InitialQueue(Q,PT,PN);
FCFS(Q,tTimeSum,WtTimeSum,PT);//先来先服务作业调度
cout<<"先来先服务的平均周转时间为:
"<cout<<"先来先服务的平均带权周转时间为:
"<delete[]PT;
return0;
}
voidinput(PCBNode*PT,intPN)
{FILE*fp;//读入进程相关内容
if((fp=fopen("input.txt","r"))==NULL)//若无法访问input文件
{cout<<"cannotopenfile!
"<exit(0);
}
for(inti=0;i{fscanf(fp,"%d%d%d",&PT[i].ATime,&PT[i].RTime,&PT[i].priority);//输入各进程从开始到全部进入就绪队列所需的时间、剩余运行时间、优先数
}
fclose(fp);
}
voidInitialQueue(LQ&Q,PCBNode*PT,intPN)
{for(inti=0;i{PT[i].PID=i;
PT[i].TrTime=PT[i].RTime;
PT[i].FTime=0;
PT[i].STime=0;
PT[i].tTime=0;
PT[i].WtTime=0;
}
Q.head=newQNode;
Q.head->next=NULL;
QNode*p;
QNode*q;
for(i=0;i{p=newQNode;
p->ID=PT[i].PID;
p->next=NULL;
if(i==0)
{Q.head->next=p;
}
elseq->next=p;
q=p;
}
}
voidRoundRobin(LQ&Q,intpiece,int&tTimeSum,int&WtTimeSum,PCBNode*PT)
{tTimeSum=0;//总的周转时间
WtTimeSum=0;//平均周转时间
intCTime=0;//当前时间
QNode*p;
QNode*q;
QNode*r;
boolfinish=false;//调用Deal()后,该进程是否已经做完退出
p=Q.head;
q=p->next;
while(q!
=NULL)//从队列首部开始依次分配时间片
{do
{cout<<"**********************"<cout<<"在时间片"<<(CTime+1)/piece+1<<"内,活动进程为:
"<ID<cout<<"进程"<ID<<"现在需要的时间片为:
"<ID].RTime<finish=Deal(Q,q,p,piece,CTime,PT);//分配时间片给q进程
cout<if(!
finish)//若是进程在本时间片内做完,则跳出do…while循环
{if(q->next==NULL)
{r=Q.head->next;
}
else
{r=q->next;
}
}
else//若未做完,计算周转时间和带权周转时间
{tTimeSum+=PT[q->ID].tTime;
WtTimeSum+=PT[q->ID].WtTime;
deleteq;//删除q进程
q=p;
}
}while(!
finish&&(PT[r->ID].ATime>CTime+piece));
p=q;//若下个进程不来,则继续给当前进程分配时间片
q=q->next;
if(q==NULL&&Q.head->next!
=NULL)
{p=Q.head;
q=p->next;
}
}
deleteQ.head;
Q.head=NULL;
}
boolDeal(LQ&Q,QNode*q,QNode*p,intpiece,int&CTime,PCBNode*PT)//分配时间片给q所指进程,p为刚退出的进程
{if(PT[q->ID].RTime<=piece)//若在此时间片内能够做完,之后退出进程调度
{PT[q->ID].FTime=CTime+PT[q->ID].RTime;
PT[q->ID].tTime+=PT[q->ID].RTime;
PT[q->ID].WtTime=PT[q->ID].tTime/PT[q->ID].TrTime;
CTime=PT[q->ID].FTime;
p->next=q->next;
cout<cout<<"进程"<ID<<"完成!
"<returntrue;
}
else//若此时间片内做不完
{PT[q->ID].RTime=PT[q->ID].RTime-piece;
PT[q->ID].tTime+=piece;
CTime+=piece;
returnfalse;
}
}
voidFCFS(LQ&Q,int&tTimeSum,int&WtTimeSum,PCBNode*PT)
{tTimeSum=0;//平均周转时间
WtTimeSum=0;//平均带权周转时间
QNode*p;
QNode*q;
p=Q.head->next;
if(p!
=NULL)//确定开始和完成时间
{PT[p->ID].STime=PT[p->ID].ATime;
PT[p->ID].FTime=PT[p->ID].ATime+PT[p->ID].TrTime;
}
for(q=p->next;q!
=NULL;q=q->next)
{if(PT[q->ID].ATimeID].FTime)
{PT[q->ID].STime=PT[p->ID].FTime;
PT[q->ID].FTime=PT[p->ID].FTime+PT[q->ID].TrTime;
}
else//若下个进程到达时间较晚
{PT[q->ID].STime=PT[q->ID].ATime;
PT[q->ID].FTime=PT[q->ID].ATime+PT[q->ID].TrTime;
}
p=q;
}
for(q=Q.head->next;q!
=NULL;q=q->next)//计算平均周转时间和平均带权周转时间
{PT[q->ID].tTime=PT[q->ID].FTime-PT[q->ID].ATime;
PT[q->ID].WtTime=PT[q->ID].tTime/PT[q->ID].TrTime;
tTimeSum+=PT[q->ID].tTime;
WtTimeSum+=PT[q->ID].WtTime;
}
intt=0;
for(q=Q.head->next;q!
=NULL;q=q->next)
{cout<<"*********************"<while(tID].FTime)
{cout<<"时刻"<进程"<ID<<"活动"<t++;
}
if(q->next!
=NULL)
{cout<<"时刻"<进程"<ID<<"结束活动,开始下一个进程。
"<cout<<"进程"<ID<<"的周转时间为:
"<ID].tTime<cout<<"进程"<ID<<"的带权周转时间为:
"<ID].WtTime<}
else
{cout<<"时刻"<进程"<ID<<"结束活动。
"<cout<<"进程"<ID<<"的周转时间为:
"<ID].tTime<cout<<"进程"<ID<<"的带权周转时间为:
"<ID].WtTime<}
}
cout<<"所有进程结束活动。
"<p=Q.head;
for(q=p->next;q!
=NULL;q=q->next)
{deletep;
p=q;
}
}
小结:
由于原课本中对于轮转法的描述过于简练,使我无法真正了解轮转法的内涵,于是我在网上查了相当量的资料并且阅读了一些与轮转法相关的实例,终于对轮转法有了基本的理解。
而在正式着手写程序前我也曾有过个疑惑:
进程调度和作业调度我究竟该分开写还是并一起写,因为两种方针都各有利弊,而最终我为了缩短时间,依然选择了将两部分合二为一,但也随之引来了如何将两者相结合的问题。
最终我另外定义了队列模块,使得进程和两种方法能相互调剂,得以解决。