实验:进程调度算法
一、实验目的
1.实现四种不同及进程调度算法:
先来先服务、时间片轮转调、优先级调度以及短作业优先调度算法。
2.通过实验理解有关进程控制块,进程队列等的概念。
二、实验要求
1.运行素材中的代码,观察其执行结果是否正确?各个调度算法的功能是否完善?如果没有,则完善。
2. 按照下表输入3个作业信息,输出使用不同调度算法的结果。
3. 在现有三个调度算法的基础上,进一步实现短作业优先调度
ProcessID | arrivetime | servicetime | priority |
1 | 1 | 9 | 2 |
2 | 4 | 6 | 3 |
3 | 6 | 3 | 1 |
说明:
1.主程序中从键盘得到进程的数量,创建PCB,调用layout()函数显示选择界面。
2.Layout()函数中选择相应的算法并调用相关函数如:FCFS(),最后打印。
三、实验素材
1、 算法流程
抽象数据类型的定义:PCB块结构体类型
struct PCB
{
int name;
int arrivetime; //到达时间
int servicetime; //服务时间
//int starttime[max]; //开始时间
int finishtime; //完成/结束时间
int turntime; //周转时间
int average_turntime; //带权周转时间
int sign; //标志进程是否完成
int remain_time; //剩余时间
int priority; //优先级
}pcb[max];
#include<stdio.h>
#include<malloc.h>
#define max 50
struct PCB//改成链表结构
{
int name;
int arrivetime; //到达时间
int servicetime; //服务时间
//int starttime[max]; //开始时间
int finishtime; //完成/结束时间
int turntime; //周转时间
int average_turntime; //带权周转时间
int sign; //标志进程是否完成
int remain_time; //剩余时间
int priority; //优先级
}pcb[max];
int least_arrive=0;
void init(int n) //初始化
{ int i;
for(i=0;i<n;i++)
{
pcb[i].arrivetime=0;
pcb[i].servicetime=0;
//pcb[i].starttime=0;
pcb[i].finishtime=0;
pcb[i].turntime=0;
pcb[i].average_turntime=0;
pcb[i].remain_time=0;
pcb[i].sign=0;
pcb[i].priority=0;
}
}
void creat(int n) //创建PCB
{
int i;
for(i=1;i<=n;i++)
{
printf("\n%d:\n input the information of process\n input processID:",i);
scanf("%d",&pcb[i].name);
printf("input the arrivetime:");
scanf("%d",&pcb[i].arrivetime);
if(pcb[i].arrivetime>pcb[least_arrive].arrivetime)
least_arrive=i;
printf("input the servicetime:");
scanf("%d",&pcb[i].servicetime);
printf("input the priority:");
scanf("%d",&pcb[i].priority);
pcb[i].remain_time=pcb[i].servicetime; //初始化剩余时间为服务时间
}
}
void FCFS(int n) //先来先服务(算法有误,只有在排好到来顺序输入进程时算法才会输出正确结果)
{
int starttime;
printf("input the start time:\n");
scanf("%d",&starttime);
if(starttime>=pcb[0].arrivetime)//指的是CPU开始执行指定进程的时间
{
pcb[0].finishtime=pcb[0].servicetime+starttime;//进程0表示CPU运行空进程
}
else
{
pcb[0].finishtime=pcb[0].finishtime+pcb[0].servicetime;
}
int i;
for(i=1;i<=n;i++)//加个=
{
if(pcb[i-1].finishtime>pcb[i].arrivetime&&least_arrive==i-1)
pcb[i].finishtime=pcb[i-1].finishtime+pcb[i].servicetime;
else if(least_arrive==i-1&&pcb[i-1].arrivetime<pcb[i].arrivetime)
pcb[i].finishtime=pcb[i].arrivetime+pcb[i].servicetime;
else
pcb[i].finishtime=pcb[least_arrive].finishtime+pcb[i].servicetime;
pcb[i].turntime=pcb[i].finishtime-pcb[i].arrivetime;
pcb[i].average_turntime=pcb[i].turntime/pcb[i].servicetime;
}
}
void print_FCFS(int n)
{
//printf("ProcessID, arrivetime\t Servicetime\t finishtime\t turntime\t:,,%s\t%d\t%d\t%d\t%d\t%d\t"); //进程名,到达时间,服务时间,完成时间,周转时间,周转时间
printf("process ID arrivetime servicetime finishtime turntime , averageturntime .\n");
int i;
for(i=0;i<=n;i++)
{
printf("%d ,%d ,%d ,%d ,%d ,%d ",pcb[i].name ,pcb[i].arrivetime ,pcb[i].servicetime ,pcb[i].finishtime ,pcb[i].turntime ,pcb[i].average_turntime);
printf("\n");
}
}
void time_segment(int n) //时间片轮转
{
int i,j;
int T; //时间片
int flag=1; //就绪队列中是否还有进程
//int time=pcb[0].arrivetime; //当前的时间
int time=0;
int sum=0; //已经完成的进程数
//按各进程的arrivetime进行升序排列
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(pcb[j].arrivetime<pcb[i].arrivetime)
{
pcb[0]=pcb[j];
pcb[j]=pcb[i];
pcb[i]=pcb[0];
}
}
//printf("output the sort result:\n");
//for(i=1;i<=n;i++) //检查排序是否正确
//printf("%d\t",pcb[i].name);
printf("input the slicetime:\n");
scanf("%d",&T);
//printf("\n running processID runtime resttime finishtime\n”) // 开始运行时间 运行时间 剩余服务时间 结束时间
while(sum<n)
{
flag=0; //当前就绪队列中没有进程
int i;
for(i=1;i<=n;i++)
{
if(pcb[i].sign==1) continue; //表示该进程已完成
else
{
//没有完成的进程需要的时间大于一个时间片
if(pcb[i].remain_time > T)
{
flag=1;
time=time+T;
pcb[i].remain_time=pcb[i].remain_time-T;
//printf("%10d%16d%12d%12d%12d\n",pcb[i].name,time-T,T,pcb[i].remain_time,time);
}
//没有完成的进程需要的时间小于或等于一个时间片
else if(pcb[i].remain_time <= T)
{
flag=1; //加入就绪队列
time=time+pcb[i].remain_time;
pcb[i].finishtime=time;
pcb[i].sign=1;
//printf("%10d%16d%12d%12d%12d\n",pcb[i].name,time-pcb[i].remain_time,pcb[i].servicetime,0,time);
pcb[i].remain_time=0;
}
if(pcb[i].sign==1) sum++;
}
}//for
if(flag==0&&sum<n) // 还有没执行的进程,且没进入就就绪队列
{
int i;
for(i=1;i<=n;i++)
if(pcb[i].sign==0) {time=pcb[i].arrivetime;break;}
}
}//while
}
void print_time(int n)
{ int i;
for(i=0;i<n;i++)
{
printf("\n processID servicetime finishtime\n"); //进程名 服务时间 完成时间
printf("%6d%10d%10d",pcb[i+1].name,pcb[i].servicetime,pcb[i].finishtime);
printf("\n");
}
}
void Priority(int n)
{
int i,j;
int time = pcb[1].arrivetime;
//按各进程的arrivetime进行升序排列,最早到达的进程先执行
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(pcb[j].arrivetime < pcb[i].arrivetime)
{
pcb[0]=pcb[j];
pcb[j]=pcb[i];
pcb[i]=pcb[0];
}
}
//printf("output the sort result: \n"); //输出排序结果
//for(i=1;i<=n;i++) //检查排序是否正确
//printf("%d\t",pcb[i].name);
printf("\n processID runtime priority fihishtime \n");//进程名 服务时间 优先级 完成时间
//先到达的进程第一个执行
if(i=1)
{
pcb[i].finishtime=pcb[i].arrivetime + pcb[i].servicetime;
time =pcb[i].arrivetime + pcb[i].servicetime;
printf("%6d%10d%10d%10d",pcb[i].name,pcb[i].servicetime,pcb[i].priority,pcb[i].finishtime);
printf("\n");
//测试第一个进程输出正确
/* printf("output the first process:\n");//输出第一个程序的
printf("processID arrivetime finishtime\n");//名称 到达时间 完成时间
printf("%4d%8d%8d",pcb[i].name,pcb[i].arrivetime,pcb[i].finishtime);
printf("\n"); */
i++;
}
//按各进程的priority进行降序排列,优先级最高的进程先执行
for(i=2;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(pcb[j].priority > pcb[i].priority)
{
pcb[0]=pcb[j];
pcb[j]=pcb[i];
pcb[i]=pcb[0];
}
}
for(i=2;i<=n;i++)
{
time = time + pcb[i].servicetime;
pcb[i].finishtime = time;
printf("%6d%10d%10d%10d",pcb[i].name,pcb[i].servicetime,pcb[i].priority,pcb[i].finishtime);
printf("\n");
}//for
}//void
void layout(int n)
{
int ch=0;
printf("\t\t************schedule algorithm************\n");
printf("\t\t1.FSFS\n");
printf("\t\t2.timesegment\n");
printf("\t\t3.priority\n");
printf(" choose the algorithm:\n");
scanf("%10d",&ch);
switch(ch)
{
case 1:
FCFS(n);
print_FCFS(n); break;
case 2:
time_segment(n);
print_time(n); break;
case 3:
Priority(n); break;
default:printf("enter error data!\n");
//P:int类型的变量,case后面不要加''
}
}
int main()
{
int n;
printf("input the number of process\n");
scanf("%d",&n);
init(n);
creat(n);
layout(n);
//FCFS(n);
//print_FCFS(n);
//time_segment(n);
//print_time(n);
//Priority(n);
return 0;
}
typedef struct{}SqQueue;
:首先定义一个循环队列的结构体用来模拟就绪队列。
struct PCB{}pcb;
:定义一个结构体类型的数组用来存放各进程运行数据。
struct link{};
:定义一个链表结构用来按照进程的到来时间进行排序并存放进程数据在数组中的下标。
init(int n):
初始化函数,按照用户输入的进程数初始化各进程数据为零
creat(int n):
创建PCB函数,根据输入的初始数据初始化各进程
sequence_arrive(int n):按照到来时间排序函数,根据每个进程的arrivetime进行排序
**FCFS(int n):**先来先服务调度函数,根据算法计算运行时间、结束时间等数据并更新pcb[]
print_FCFS(int n):
先来先服务输出函数
time_segment(int n):
时间片轮转调度函数,根据算法计算运行时间、结束时间等数据并 更新pcb[]
print_time(int n):
时间片轮转输出函数
Priority(int n):
非抢占优先级调度函数,根据算法计算运行时间、结束时间等数据并更 新pcb[]
SJF(int n):
短作业优先调度函数,根据算法计算运行时间、结束时间等数据并更新pcb[]
layout(int n):
算法选择函数,显示选择界面并根据用户选择调度不同算法对应函数
main():
主函数,调配不同的函数以完成本次验证实验
1、先来先服务进程调度算法运行结果及分析
算法说明:
第一次按照到来顺序输入进程,第二次调整顺序,输出结果一样,验证了算法的正确性。
函数主要调用了按照到来时间排序函数,根据已排好序的链表,结合上一进程的结束时间以及此进程的服务时间计算出此进程的结束时间、运行时间、周转时间、带权周转时间等,并更新pcb[]。
2、时间片轮转进程调度算法运行结果及分析
算法说明:
第一次输入按照到来时间顺序输入,时间片设为1;第二次乱序输入,时间片设为4,经验证两次结果均正确(算法中先把本次时间片结束后,若当前进程未执行完毕,则先将当前进程入队,再查看已到来进程并入队。这里与真正的时间片轮转相比是一个错误,但由于时间紧急,未进行修改)
函数先使用排序函数进行排序,并根据排号的序列检查对于当前时间是否已有新的进程到来,若到来,则使用队列依次存储到来进程在pcb[]中的下标。每次完成一个时间片就开始检查是否有新的进程到来,并加入队列。若队列中已就绪的进程均执行完毕且仍有部分进程没有到来,便让时间增加,每次增加都判断是否有进程到来。
对于从队列取出的进程:如果进程剩余执行时间大于时间片,则减去一个时间片,并使当前时间增加一个时间片;否则进程剩余时间不足一个时间片,进程的结束时间即当前时间加上剩余时间,当前时间time增加量为此进程的剩余时间。
3、非抢占式优先级调度算法运行结果及分析
算法说明:
输入时没有按照优先级顺序输入,而是乱序输入,经验证结果正确
同样此函数使用了排序函数以及队列,按照排好的顺序依次将进程进队,之后从队列中循环查看各进程的优先级,并保存优先级最高进在pcb[]中的下标,同时将队列中此元素的优先级降到最小(利用pcb[]0号单元,因为它的优先级为0),另外,为了防止0号单元的空进程占用时间,在执行时先判断下标是否为0。
4、短作业优先调度算法运行结果及分析
算法说明:
此算法和优先级算法相似,只是其中对于优先级最大变成了执行时间最少