实验3 进程调度
一、实验目的
多道程序系统中,当就绪进程数大于处理机数时,须按照某种策略决定哪些进程优先占用处理机。本实验模拟实现进程调度算法,以加深对进程概念和调度算法的理解。
二、实验要求
(1)问题描述
编程实现多级反馈队列调度算法,并给出各个进程的完成时间、周转时间、带权周转时间、以及平均带权周转时间。
(2)基本要求
- 至少能实现三级反馈队列(即至少包括三个就绪队列,分别为队列1、队列2、队列3);
- 需考虑进程被阻塞的情况,以及调度过程中有新进程到到达的情况;
- 要求展现出调度的过程。
三、设计
(1) 多级反馈队列调度算法的基本思想:
设置多个就绪队列,并为各个队列赋予不同的优先级。
第一个队列的优先级最高,第二个队列次之,其余各队列的优先级逐个降低;在优先级愈高的队列中,为每个进程所规定的执行时间片愈小。
当一个新进程进入内存后,先将它放入第一队列末尾,按FCFS等待调度。
当轮到它执行时,如能在该时间片内完成,便可准备撤离;
如在一个时间片结束时尚未完成,调度程序便将其降入第二队列末尾,再同样地按FCFS原则等待调度执行;
如在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第n队列中便采取按RR方式运行。
(2)主要功能模块
- 进程初始化;
- 显示初始化后进程的基本信息;
- 多级反馈队列调度(包括当前进程被阻塞、检查是否有高优先级的进程);
- 若当前进程没被阻塞,且剩余的服务时间不为0,则当前进程进入下一级队列的队尾(需进行特殊情况的检查:若当前进程已在最后一个队列中,则进入原队列的队尾)。
- 若当前进程被阻塞,要将该进程放入相应的阻塞队列,并且要记录下被阻塞时所处的队列编号,以便于唤醒时回到原队列中;
- 每运行一个时间单位,需判断是否有高优先级进程进入系统或被唤醒,若有,则调度该优先级高的进程(即高优先级队列中的进程),否则,仍调度当前队列中的进程;
- 若当前队列为空,则调度下一级队列中的进程。
- 显示调度的过程以及各进程的完成时间、周转时间、带权周转时间,以及平均带权周转时间。
(3)输入
进程数、进程标识、进程的到达时间、服务时间、优先级、对应的时间片大小等。由于新创建的进程先进入队列1中,因此,此处优先级就是队列1(即最高优先级队列)的优先级,时间片大小就是队列1的时间片大小,而其余各队列的时间片以该时间片为基础计算而得,例如:若初始化的时间片q1=1,则另外两个队列的时间片可分别为是q2=q1*2、q3=q2*2;对于优先级也可用类似方法进行处理,如p1=10,p2=p1-2,p3=p2-2。注意初始化进程时,各进程所对应的时间片大小以及优先级都是一样的,都是队列1对应的优先级以及时间片大小。
如:
进程数:2
进程的初始化:
1,0,3,10,1
2,2,2,10,1
由上述初始化信息,可知队列1的优先级为10,时间片大小为1
(4)输出
显示调度的过程(如哪个时刻调度队列X中的进程Y,运行多长时间,还需服务时间等),以及各个进程名、对应的完成时间、周转时间和带权周转时间和整体的平均带权周转时间。
四、实验代码
1.PCB设计-多级反馈.h
#include <stdio.h>
#include <malloc.h>
#include <queue> //
using namespace std;//调用命名空间std内定义的所有标识符
typedef struct PCB{//PCB数据结构的设计
int id;//进程标识符
int arrivetime; //到达时间
int servetime;//服务时间
int finishtime;//完成时间
int priority;//优先级
int timep;//时间片大小
struct PCB *next;//设置PCB为链接方式
}PCB;
2.进程初始化
#include "多级反馈.h"
int time=0;
float sum=0;
//进程初始化
void InitPCB(PCB &work, int id, int arrivetime, int servetime, int priority, int timep){
work.id=id;
work.arrivetime=arrivetime;
work.servetime=servetime;
work.priority=priority;
work.timep=timep;
}
3.队列一和队列二执行FCFS算法
//队列1和队列2执行fcfs算法
void fcfs(queue<PCB> &q1, queue<PCB> &q2,int id){
printf("\n第%d级(fcfs)\n",id);
//当一个新进程进入内存后,先将它放入第一队列末尾,按FCFS等待调度。
while(!q1.empty()){
PCB s=q1.front();
printf("时间:%d ",time);
if(time>=s.arrivetime){
printf("进程%d 运行时间%d ",s.id,s.timep);
//运行一个时间片
for(int i=0;i<s.timep;i++){
time++;
s.servetime--;
}
s.timep=s.timep*2;
s.priority-=2;
//若运行完成
if(s.servetime<=0){
s.finishtime=time; //结束时间
int zhouzhuan=s.finishtime-s.arrivetime; //周转时间
float daiquan=((float)zhouzhuan)/(s.servetime+timeloss(id));//带权周转时间
printf("运行完成 ");
printf("完成时间%d 周转时间%d 带权周转时间%.1f\n",s.finishtime,zhouzhuan,daiquan);
sum+=daiquan;
q1.pop();//已完成的进程离开系统
continue;
}else{//若运行未完成
q1.pop(); //已执行一次的进程离开队列 1
q2.push(s);//转入队列2
printf("还需服务时间%d\n",s.servetime);
}
}else{//等待进程到达
time++;
printf("\n");
}
}
//循环结束,q1为空,展示q2
printf("第%d级执行完成,下级进程:\n",id);
dispQueue(q2);
}
4.队列三执行时间片轮转算法
//队列3执行时间片轮转算法
float rr(queue<PCB> &q3){
printf("\n第3级(rr)\n");
while(!q3.empty()){
PCB s=q3.front();
printf("时间:%d ",time);
if(time>=s.arrivetime){
printf("进程%d 运行时间%d ",s.id,s.timep);
//运行一个时间片
for(int i=0;i<s.timep;i++){
time++;
s.servetime--;
}
//若运行完成
if(s.servetime<=0){
s.finishtime=time; //结束时间
int zhouzhuan=s.finishtime-s.arrivetime; //周转时间
float daiquan=(zhouzhuan*1.0)/(s.servetime+timeloss(3));//带权周转时间
printf("运行完成 ");
printf("完成时间%d 周转时间%d 带权周转时间%.1f\n",s.finishtime,zhouzhuan,daiquan);
sum+=daiquan;
q3.pop();//已完成的进程离开系统
continue;
}else{//若运行未完成
q3.pop(); //先出队列3
q3.push(s);//再入队列3
printf("还需服务时间%d\n",s.servetime);
}
}else{
time++;
}
}
//循环结束
printf("所有进程执行完成\n");
return sum; //返回带权周转时间的和
}
各级执行过的时间片数量
//计算进程在各级执行过的时间片数量
int timeloss(int n){
int i,j,time=0;
for(i=0,j=1;i<n;i++,j*=2){
time+=j;
}
return time;
}
5.多级反馈主函数
#include "多级反馈.cpp"
int main (){
PCB work;
queue<PCB> q1,q2,q3;//队列1,2,3
float avg,sum;
int n;//进程数
int id,arrivetime,servetime,priority,timep;
//初始化进程
printf("请输入进程数:");
scanf("%d",&n);
printf("请输入进程标识,到达时间,服务时间,优先级,对应的时间片大小:\n");
for(int i=0;i<n;i++){
scanf("%d%d%d%d%d",&id,&arrivetime,&servetime,&priority,&timep);
InitPCB(work,id,arrivetime,servetime,priority,timep);
q1.push(work);//进程入队列1执行
}
printf("初始化完成,队列1信息:\n");
dispQueue(q1);
//多级反馈队列调度算法
fcfs(q1,q2,1); //第一级
fcfs(q2,q3,2); //第二级
sum=rr(q3); //第三级
avg=sum/n;
printf("平均带权周转时间为%.2f\n",avg);
return 0;
}