实验一 进程调度实验
【实验目的】
(1)加深对进程的概念及进程调度算法的理解;进行程序设计的训练。
(2)进程调度是处理机管理的核心内容。通过自己编写和调试个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解先来先服务、短作业优先、高优先权优先调度等算法的具体实施办法。
【实验内容】
设计一个有 N个进程并发执行的进程调度模拟程序。
进程调度算法:(1)先来先服务调度算法:先按照进入CPU的时间将所有进程一次存入队列 ( 先进入CPU的存在靠近队首位置),然后每次将队首位置的进程调入内存,为他分配资源,投入运行,直到该进程完全运行完毕,再接着调入队首进程,直到队列为空。
(2) 短作业优先调度算法:先将所有就绪队列按照剩余时间由小到大的顺序排列,并依次存入队列,再按照先来先服务方法执行下去。
1.每个进程有一个进程控制块(PCB)表示。进程控制块包含如下信息:进程名、优先级、到达时间、需要运行时间、已用CPU时间、进程状态等等。
2.进程的优先级及需要的运行时间可以事先人为地指定,进程的运行时间以时间片为单位进行计算。
3.就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。
4.如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待调度。
5.每进行一次调度程序都打印一次运行进程、就绪队列中各个进程的 PCB,以便进行检查。
6.重复以上过程,直到所要进程都完成为止。
【设计思路】
在OS中调度的实质是一种资源分配,因而调度算法是指:根据系统的资源分配策咯所规定的资源分配算法。进程调度常用的算法有:先来先服务调度、优先级调度、时间片轮转调度和多级反馈队列调度。本次实验就是将模拟先来先服务、短作业优先、两种调度算法进行设计并对他们的性能进行比较,程序提供了创建进程,选择进程调度算法的基本功能。
首先应该设计数据结构,创建进程结构体,然后认真设计每一个进程调度的算法,并运用程序加以实现,算法设计完毕后调试整体程序并测试,比较在不同环境下各种进程调度的优劣。
目前存在的多种调度算法中,有的短发适用于作业调度,有的算法适用于进程调度;但也有些调度算法既可用于作业调度,也可用于进程调度。
【流程框图】
【主要程序代码】
#include<stdio.h>
#define N 50
int main()
{
void xfw(); //先来先服务
void dzy(); //短作业优先
int a;
while(true)
{
printf("\n\n");
printf(" 请选择其一调度算法:");
printf("\n 1、先到先服务调度 ");
printf("\n 2、短作业优先调度 ");
printf("\n 0、 退 出 \n");
printf("\n\n 请选择菜单项:");
scanf("%d",&a);
printf("\n");
switch(a){
case 1: xfw();break;
case 2: dzy();break;
default: break;
}
if(a<0&&a>3) break;
}
}
void xfw()
{
int i,j,n,min,px; //n:进程个数 px:输出方式选择
float sum1,sum2;
printf("请输入有n个进程(0<n<=50):");
scanf("%d",&n);
while(n>50||n<=0)
{
printf("n请重新输入:");
scanf("%d",&n);
}
printf("\n\n");
struct PCB{
int id; //进程名字
int dt; //到达时刻
int st; //服务时间
int wct; //完成时刻
float zt; //周转时间
float dczt; //带权周转时间
};
PCB a[N];
for(i=0;i<n;i++)
{
a[i].id=i+1;
printf("进程%d 到达时间:",a[i].id);
scanf("%d",&a[i].dt);
printf("进程%d 服务时间:",a[i].id);
scanf("%d",&a[i].st);
printf("\n");
}
for(j=n-1;j>=0;j--)
{
for(i=0;i<j;i++)
{
if(a[i].dt>a[i+1].dt)
{
min=a[i].id;
a[i].id=a[i+1].id;
a[i+1].id=min;
min=a[i].dt;
a[i].dt=a[i+1].dt;
a[i+1].dt=min;
min=a[i].st;
a[i].st=a[i+1].st;
a[i+1].st=min;
}
}
}
a[0].wct=a[0].dt+a[0].st; //完成时刻=到达时刻+服务时间
a[0].zt=(float)a[0].st; //第一个 周转时间=服务时间
a[0].dczt=a[0].zt/a[0].st; //带权周转时间=周转时间/服务时间
for(i=1;i<n;i++)
{
if(a[i].dt>a[i-1].wct) //当 a[i]到达时刻>a[i-1]完成时刻
{
a[i].wct=a[i].dt+a[i].st; //a[i]完成时刻=到达时刻+服务时间
a[i].zt=(float)a[i].st; //此时,周转时间=服务时间
a[i].dczt=a[i].zt/a[i].st; //带权周转时间=周转时间/服务时间
}
else
{
a[i].wct=a[i-1].wct+a[i].st; //a[i]完成时刻=a[i-1]完成时刻+a[i]服务时间
a[i].zt=(float)(a[i].wct-a[i].dt); //周转时间=完成时刻-到达时刻
a[i].dczt=a[i].zt/a[i].st; //带权周转时间=周转时间/服务时间
}
}
printf("1、按id号依次输出\n");
printf("2、按完成顺序依次输出\n");
printf("\n请选择输出顺序:");
scanf("%d",&px);
printf("\nid:到达时间\t服务时间\t完成时间\t周转时间\t带权周转时间\n");
sum1=0;
sum2=0;
switch(px)
{
case 1: //1.按id号依次输出
{
for(j=0;j<n;j++)
{
for(i=0;i<n;i++)
if(a[i].id==j+1)
{
printf("%d: %d\t\t%d\t\t%d\t\t%.0f\t\t%.2f\n",a[i].id,a[i].dt,a[i].st,a[i].wct,a[i].zt,a[i].dczt);
sum1+=a[i].zt;
sum2+=a[i].dczt;
}
}
printf("\n平均周转时间:%.2f\n",sum1/n);
printf("\n平均带权周转时间:%.2f\n\n",sum2/n);
break;
}
case 2: //2.按完成顺序依次输出
{
for(i=0;i<n;i++)
{
printf("%d: %d\t\t%d\t\t%d\t\t%.0f\t\t%.2f\n",a[i].id,a[i].dt,a[i].st,a[i].wct,a[i].zt,a[i].dczt);
sum1+=a[i].zt;
sum2+=a[i].dczt;
}
printf("\n平均周转时间:%.2f\n",sum1/n);
printf("\n平均带权周转时间:%.2f\n\n",sum2/n);
break;
}
default: break;
}
}
void dzy()
{
int i,j,n,min,px; //n:进程个数 px:输出方式选择
int b=0,z;
float sum1,sum2;
printf("\n请输入有n个进程(0<n<=50): ");
scanf("%d/n",&n);
while(n>50||n<=0)
{
printf("n请重新输入:");
scanf("%d",&n);
}
printf("\n");
struct PCB{
int id; //进程名字
int dt; //到达时刻
int st; //服务时间
int wct; //完成时刻
float zt; //周转时间
float dczt; //带权周转时间
};
PCB a[N];
for(i=0;i<n;i++)
{
a[i].id=i+1;
printf("进程%d 到达时间:",a[i].id);
scanf("%d",&a[i].dt);
printf("进程%d 服务时间:",a[i].id);
scanf("%d",&a[i].st);
printf("\n");
}
min=a[0].dt;
for(j=n-1;j>=0;j--)
{
for(i=0;i<j;i++)
{
if(a[i].dt>a[i+1].dt) //如果a[i]的到达时刻>a[i+1]的到达时刻
{
min=a[i].id;
a[i].id=a[i+1].id;
a[i+1].id=min;
min=a[i].dt;
a[i].dt=a[i+1].dt;
a[i+1].dt=min;
min=a[i].st;
a[i].st=a[i+1].st;
a[i+1].st=min;
}
if(a[i].dt==a[i+1].dt&&a[i].st>a[i+1].st) //同时到达且a[i]更短
{
min=a[i].id;
a[i].id=a[i+1].id;
a[i+1].id=min;
min=a[i].dt;
a[i].dt=a[i+1].dt;
a[i+1].dt=min;
min=a[i].st;
a[i].st=a[i+1].st;
a[i+1].st=min;
}
}
}
a[0].wct=a[0].st+a[0].dt;
a[0].zt=(float)a[0].st;
a[0].dczt=a[0].zt/a[0].st;
for(i=1;i<n;i++)
{
if(a[i].dt>a[0].wct) ;
else b=b+1;
}
for(j=b-1;j>=1;j--)
{
for(i=1;i<j;i++)
{
if(a[i].st>a[i+1].st)
{
min=a[i].dt;
a[i].dt=a[i+1].dt;
a[i+1].dt=min;
min=a[i].st;
a[i].st=a[i+1].st;
a[i+1].st=min;
min=a[i].id;
a[i].id=a[i+1].id;
a[i+1].id=min;
}
}
}
for(i=1;i<n;i++)
{
if(a[i].dt>a[i-1].wct)
{
a[i].wct=a[i].dt+a[i].st;
a[i].zt=(float)a[i].st;
a[i].dczt=a[i].zt/a[i].st;
}
else
{
a[i].wct=a[i-1].wct+a[i].st;
a[i].zt=(float)(a[i].wct-a[i].dt);
a[i].dczt=a[i].zt/a[i].st;
}
for(j=i+1,b=j;j<n;j++)
{
if(a[j].dt>a[i].wct) ;
else b=b+1;
}
for(j=b-1;j>=i;j--)
{
for(z=i;z<j;z++)
{
if(a[z].st>a[z+1].st)
{
min=a[z].dt;
a[z].dt=a[z+1].dt;
a[z+1].dt=min;
min=a[z].st;
a[z].st=a[z+1].st;
a[z+1].st=min;
min=a[i].id;
a[i].id=a[i+1].id;
a[i+1].id=min;
}
}
}
}
printf("\n请选择输出顺序\n");
printf("1、按id号依次输出\n");
printf("2、按完成顺序依次输出\n");
scanf("%d",&px);
printf("\nid:到达时间\t服务时间\t完成时间\t周转时间\t带权周转时间\n");
sum1=0;
sum2=0;
switch(px)
{
case 1: //1、按id号依次输出
{
for(j=0;j<n;j++)
{
for(i=0;i<n;i++)
if(a[i].id==j+1)
{
printf("%d: %d\t\t%d\t\t%d\t\t%.0f\t\t%.2f\n",a[i].id,a[i].dt,a[i].st,a[i].wct,a[i].zt,a[i].dczt);
sum1+=a[i].zt;
sum2+=a[i].dczt;
}
}
printf("\n平均周转时间:%.2f\n",sum1/n);
printf("\n平均带权周转时间:%.2f\n\n",sum2/n);
break;
}
case 2: //2、按完成顺序依次输出
{
for(i=0;i<n;i++)
{
printf("%d: %d\t\t%d\t\t%d\t\t%.0f\t\t%.2f\n",a[i].id,a[i].dt,a[i].st,a[i].wct,a[i].zt,a[i].dczt);
sum1+=a[i].zt;
sum2+=a[i].dczt;
}
printf("\n平均周转时间:%.2f\n",sum1/n);
printf("\n平均带权周转时间:%.2f\n\n",sum2/n);
break;
}
default: break;
}
}
【测试结果】
1.先来先服务调度:
2.短作业优先调度:
【实验总结】
通过这次课程设计,使我更加扎实的掌握了有关操作系统方面的知识,特别是进程以及各种调度算法。进程调度虽然是在系统内部的低级调度,但进程调度的优劣直接影响作业调度的性能。反映作业调度优劣的周转时间和平均周转时间只在某种程度上反映了进程调度的性能,例如,其执行时间部分中实际上包含有进程等待(包括就绪状态时的等待)时间,而进程等待时间的多少是要依靠进程调度策略和等待事件何时发生等来决定的。因此,进程调度性能的商量是操作系统设计的一个重要指标。所以进程调度的重要性也是不可忽视的。