先来先服务、短进程优先算法

一.实验目的

  通过使用c对先来先服务、短进程优先算法的实现,进一步理解并掌握调度算法的逻辑过程,以及每种算法分别在进程调度和作业调度中的的处理方法.

二.实验原理

先来先服务:该算法在每次调度中,都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为他们分配资源、创建进程,然后放入就绪队列。在进程调度中采用FCFS算法时,则每次调度是从就绪队列中选择一个最先进入该队列的进程,位置分配处理机,使之投入运行。该进程一直运行到完成或发生某事件而阻塞后才放弃处理机。

短进程优先:该调度算法是从后备序列中选择一个或若干个估计运行时间最短的作业,将他们调入内存运行。

三.实验流程图

wKioL1abTA_gTdZqAAAbFiNK1R8980.png

wKiom1abS-_D_u2oAAAXr9X5sxE613.png

四.程序清单

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
#define getpch(type) (type*)malloc(sizeof(type)) 
int n; 
float T1=0,T2=0;
int times=0;   
 
struct jcb      //作业控制块 
{   
char name[10];  //作业名  
int reachtime;   //作业到达时间  
int starttime;    //作业开始时间   
int needtime;       //作业需要运行的时间 
int finishtime;       //作业完成时间  
float cycletime;       //作业周转时间  
float cltime;           //作业带权周转时间 
char state;            //作业状态 
struct jcb *next;      //结构体指针
}*ready=NULL,*p,*q; 
 
typedef struct jcb JCB; 
 
void inital()   //建立作业控制块队列,先将其排成先来先服务的模式队列
{
int i;
printf("\n输入作业数:");
scanf("%d", &n);
for (i = 0; i<n; i++)    
{
p = getpch(JCB);       
printf("\n输入作业名:");         
scanf("%s", p->name);      
getchar();        
p->reachtime = i;       
printf("作业默认到达时间:%d", i);      
printf("\n输入作业要运行的时间:");      
scanf("%d", &p->needtime);    
p->state = 'W';    
p->next = NULL;       
if (ready == NULL)  
ready = q = p;      
else
{ 
q->next = p;        
q = p; 
} 
}
}
 
void disp(JCB*q,int m)    //显示作业运行后的周转时间及带权周转时间等
{
printf("\n作业%s正在运行,估计其运行情况:\n",q->name);   
printf("开始运行时刻:%d\n",q->starttime);    
printf("完成时刻:%d\n",q->finishtime); 
printf("周转时间:%f\n",q->cycletime);  
printf("带权周转时间:%f\n",q->cltime);   
getchar();  
}
 
void running(JCB *p, int m)  //运行作业
{
if (p == ready)          //先将要运行的作业从队列中分离出来 
{
ready = p->next;
p->next = NULL;
}
else
{
q = ready;
while (q->next != p)  q = q->next;
q->next = p->next;
}
p->starttime = times;    //计算作业运行后的完成时间,周转时间等等 
p->state = 'R';
p->finishtime = p->starttime + p->needtime;
p->cycletime = (float)(p->finishtime - p->reachtime);
p->cltime = (float)(p->cycletime / p->needtime);
T1 += p->cycletime;
T2 += p->cltime;
disp(p, m);        //调用disp()函数,显示作业运行情况     
times += p->needtime;
p->state = 'F';
printf("\n%s has been finished!\n", p->name);
free(p);          //释放运行后的作业 
getchar();
}
 
void final() //最后打印作业的平均周转时间,平均带权周转时间 
{    
float s,t;   
t=T1/n;  
s=T2/n;   
getchar();   
printf("\n\n作业已经全部完成!\n");   
printf("\n%d个作业的平均周转时间是:%f",n,t);   
printf("\n%d个作业的平均带权周转时间是%f:\n\n\n",n,s); 
} 

void sjf(int m)      // 最短作业优先算法
{     
JCB *min;  
int i,iden;  
system("cls");    
inital();   
for(i=0;i<n;i++)
{          
p=min=ready;
iden=1;  
do{       
if(p->state=='W'&&p->reachtime<=times)     
if(iden)
{                  
min=p;
iden=0;    
}              
else if(p->needtime<min->needtime) min=p;          
p=p->next;     
} while (p != NULL);
if(iden)
{        
i--;  
times++;      
if (times>100)
{ 
printf("\nruntime is too long...error"); 
getchar(); 
}
}
else
{
running(min, m);      
}    
}    
final();      
} 

void fcfs(int m)     //先来先服务算法
{ 

int i, iden;   
system("cls");    
inital();     
for (i = 0; i<n; i++)  
{

p = ready;
iden = 1;    
do{
if (p->state == 'W'&&p->reachtime <= times)  iden = 0;          
if (iden)p = p->next;
} while (p != NULL&&iden);
if (iden)           
{
i--;     
printf("\n没有满足要求的进程,需等待");         
times++;          
if (times>100)
{ 
printf("\n时间过长"); 
getchar();
}
}
else
{
running(p, m);  
}     
}   
final();      
} 

void menu()
{
int m;   
system("cls");  
printf("\n\n\t\t*********************************************\t\t\n");
printf("\t\t\t\t作业调度演示\n");  
printf("\t\t*********************************************\t\t\n");  
printf("\n\n\n\t\t\t1.先来先服务算法."); 
printf("\n\t\t\t2.最短作业优先算法."); 
printf("\n\t\t\t0.退出程序.");  
printf("\n\n\t\t\t\t选择所要操作:"); 
scanf("%d", &m);
switch (m)  
{
case 1:      
fcfs(m);  
getchar();      
system("cls");  
break;  
case 2:   
sjf(m);   
getchar();    
system("cls");     
break;    
case 0:   
system("cls"); 
break;  
default:   
printf("选择错误,重新选择.");  
getchar();       
system("cls");   
menu();
}
}
int main() 
{       
menu();
system("pause");
return 0;
   }

五.实验结果截图

wKiom1abTI_BAn54AAAPJLxG6os388.png

1.先来先服务算法:

wKioL1abTPGz_09kAAAzaLRv5u4107.png

wKiom1abTOnQQGMwAAAZyWJBVGo126.png

wKioL1abTS_ylOrVAAAbMASswfE463.png

wKiom1abTQnCLw1gAAAGeUhRfKY053.png

2.短作业优先算法:

wKioL1abTXqy4oU6AAAyQgKQj-A369.png

wKiom1abTVKAEnWQAABG9PzpZ9w903.png

wKioL1abTZbTnGLqAABE-gUlWxo888.png

wKiom1abTW-waphyAABMibs3p50395.png

六.结果分析

先来先服务算法比较有利于长作业,而不利于短作业。根据先来先服务的实验,短作业C的带权周转时间竟高达100,这是不能容忍的;而长作业D的带权周转时间仅为1.99。就此可知,先来先服务算法有利于CPU繁忙型作业,而不利于I/O繁忙型作业。

根据实验得知,短作业优先调度算法能有效的降低作业的平均等待时间,提高吞吐量。但同时,该算法对长作业不利,更严重的是,如果有一长作业进入系统的后备队列,由于调度程序总是优先调度那些短作业,将导致长作业长期不被调度。该算法完全未考虑作业的紧迫程度,因而不能保证紧迫性作业会被及时处理。