- 先来先服务
先来先服务(FCFS: first come first service)总是把当前处于就绪队列之首的那个进程调度到运行状态。也就说,它只考虑进程进入就绪队列的先后,而不考虑它的下一个CPU周期的长短及其他因素。FCFS算法简单易行,是一种非抢占式策略。
2.短进程优先调度
最短进程优先算法是一种非剥夺式算法,总是选取预计作业时间最短的作业优先运行;最短剩余时间优先算法是非剥夺式的,但可以改造成剥夺式的调度算法,称抢占式最短作业优先算法。
至于二者的平均周转时间,比如有四个进程P1,P2,P3,P4,分别在0,1,2,3时刻到达,所需时间分别为7,5,3,8;那么其平均周转时间为((15-0)+(9-1)+(5-2)+(23-15))/4=8.5;
公式:
完成时间 = 开始时间 + 需要运行时间
周转时间 = 完成时间 - 到达时间
带权周转时间 = 周转时间 / 需要运行时间
3.时间片轮转算法
时间片轮转法(Round-Robin,RR)主要用于分时系统中的进程调度。为了实现轮转调度,系统把所有就绪进程按先入先出的原则排成一个队列。新来的进程加到就绪队列末尾。每当执行进程调度时,进程调度程序总是选出就绪队列的队首进程,让它在CPU上运行一个时间片的时间。时间片是一个小的时间单位,通常为10~100ms数量级。当进程用完分给它的时间片后,系统的计时器发出时钟中断,调度程序便停止该进程的运行,把它放入就绪队列的末尾;然后,把CPU分给就绪队列的队首进程,同样也让它运行一个时间片,如此往复。
以下为上面三个算法的代码:(先来先服务和最短进程调度都为进程随机获得)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
//进程控制块(PCB)
struct PCB
{
char name;
int arrivetime;
int servetime;
int finishtime;
float roundtime;
float daiquantime;
int sc; //sign completion标志是否完成
int st1; //剩余服务时间
};
struct PCB a[50];
struct PCB b[50];
char *jczt[] = { "运行", "就绪" };//*表示没有字符串的大小限制
//打印统计信息
void tjxx(int n)
{
float averoundtime = 0.0f;
float avedaiquantime = 0.0f;
printf("按任意键查看统计信息");
getchar(); getchar();
printf("\n\n进程名称\t到达时间\t服务时间\t完成时间\t周转时间\t带权周转时间");
for (int j = 0; j < n; j++)
{
printf("\n %c\t\t%4d\t\t%4d\t\t%d\t\t%4.f\t\t %.2f\n", a[j].name, a[j].arrivetime, a[j].servetime, a[j].finishtime, a[j].roundtime, a[j].daiquantime);
averoundtime += a[j].roundtime;
avedaiquantime += a[j].daiquantime;
}
printf("\n平均周转时间:%.2f", averoundtime / n);
printf("\n\n平均带权周转时间:%.2f\n", avedaiquantime / n);
}
//先来先服务
void fcfs(int n)
{
int time = 0; //定义当前时刻
int processnum = 0; //定义当前进程指向
struct PCB t; //定义一个空的结构体节点
int processztsy = 0; //定义进程状态索引
while (1)
{ printf("当前时刻:%2d\n", time);
//排序
for (int i = 1; i < n; i++)
{ for (int j = 0; j < n - i; j++)
{ if (a[j].arrivetime > a[j+1].arrivetime)//先到先运行
{ t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
if (a[j].arrivetime == a[j + 1].arrivetime)//进程同时到
{ if (a[j].servetime > a[j + 1].servetime)//比较服务时间,将运行时间短的放在优先级高的位置
{ t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}
for (int k = 0; k< n; k++)
{ if (time == a[k].arrivetime && a[k].arrivetime != 0)
{ if (k >= 1 && time >= a[k - 1].finishtime || k == 0)
processztsy = 0;
else
processztsy = 1;
printf("\t\t进程 %c 到达\t进程状态\n", a[k].name);
printf("\n\t\t\t\t %s\n\n", jczt[processztsy]);
if (processnum >= 1)
{
a[k].finishtime = a[k-1].finishtime + a[k].servetime;
a[k].roundtime =(float)(a[k].finishtime - a[k].arrivetime);
a[k].daiquantime = a[k].roundtime / a[k].servetime;
}
if (processnum == 0)
{
a[k].finishtime = a[k].arrivetime + a[k].servetime;
a[k].roundtime =(float)(a[k].finishtime-a[k].arrivetime);
a[k].daiquantime = a[k].roundtime / a[k].servetime;
printf("\t\t\t进程 %c 开始\n\n", a[processnum].name);
processnum++;
}
}
if (time == a[k].finishtime && a[k].finishtime != 0)
printf("\t\t\t进程 %c 完成\n\n", a[k].name);
if ((k >= 1 && time >= a[k].arrivetime && time == a[k - 1].finishtime && a[k].arrivetime != 0))
printf("\t\t\t进程 %c 开始\n\n", a[k].name);
}
if (time > a[n-1].finishtime && a[n-1].finishtime != 0)
{
printf("\t\t\t所有进程已进程已加载完毕!\n\n");
break;
}
time++;
Sleep(1000);
}
tjxx(n);
}
//短进程有先算法
void spf(int n)
{
struct PCB t;
int time = 0;//定义当前时刻
int jcnum = 0;
int jcztsy = 0;
bool ztgb = false;
//排序
for (int i = 1; i < n; i++)
{ for (int j = 0; j < n-i; j++)
{ if (a[j].arrivetime > a[j+1].arrivetime)//先到达的优先级高
{ t=a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
while (1)
{ printf("当前时刻:%d\n", time);
//遍历数组,注意同时达到的进程,所以采用for循环遍历
for (int k = 0; k< n; k++)
{ //是否有进程的到达时间等于当前时刻
if (time == a[k].arrivetime && a[k].arrivetime != 0)
{ //判断到达进程因该处于什么状态
if (k >= 1 && time >= a[k - 1].finishtime || k == 0)
jcztsy = 0;
else
jcztsy = 1;
printf("\t\t进程 %c 到达\t进程状态\n\n\n\n", a[k].name);
}
}
if (jcnum == 0)
{ //遍历数组
for (int i = jcnum; i < n; i++)
{ //把当前到达的进程筛选出来
if (time >= a[i].arrivetime)
{ //从挑选出来的进程中选取服务时间最短的一个
if (a[i].servetime < a[jcnum].servetime)
{ t = a[jcnum];
a[jcnum] = a[i];
a[i] = t;
}
ztgb = true;
}
}
if (ztgb == true)
{ printf("\t\t\t进程 %c 开始\n\n\n\n", a[jcnum].name);
a[jcnum].finishtime = a[jcnum].arrivetime + a[jcnum].servetime;
a[jcnum].roundtime =(float)(a[jcnum].finishtime - a[jcnum].arrivetime);
a[jcnum].daiquantime = a[jcnum].roundtime / a[jcnum].servetime;
ztgb = false;
jcnum++;
}
}
if (time == a[jcnum - 1].finishtime && a[jcnum - 1].finishtime != 0)
{ printf("\t\t\t进程 %c 完成\n\n\n\n", a[jcnum - 1].name);
//遍历数组
for (int i = jcnum; i < n; i++)
{ //把当前到达的进程筛选出来
if (time >= a[i].arrivetime)
{ //从挑选出来的进程中选取服务时间最短的一个
if (a[i].servetime < a[jcnum].servetime)
{ t = a[jcnum];
a[jcnum] = a[i];
a[i] = t;
}
ztgb = true;
}
}
if (ztgb == true || jcnum == n-1)
{
printf("\t\t\t进程 %c 开始\n\n\n\n", a[jcnum].name);
a[jcnum].finishtime = a[jcnum - 1].finishtime + a[jcnum].servetime;
a[jcnum].roundtime =(float)(a[jcnum].finishtime - a[jcnum].arrivetime);
a[jcnum].daiquantime = a[jcnum].roundtime / a[jcnum].servetime;
ztgb = false;
jcnum++;
}
}
if (time > a[n - 1].finishtime && a[n - 1].finishtime != 0)
{
printf("\t\t\t所有进程已加载完毕! \n\n\n\n");
break;
}
time++;
Sleep(1000);
}
tjxx(n);
}
//时间片轮转算法
void rr(int n)
{ struct PCB t;
int i,j,T;
printf("\n请输入时间片:\n");
scanf("%d",&T);
for(i=0;i<n;i++) //收集进程信息
{
a[i].sc=0;
printf("\n%d:\n请依次输入进程的信息\n请输入进程名:",i+1);
scanf("%s",&a[i].name);
printf("请输入到达时间:");
scanf("%d",&a[i].arrivetime);
printf("请输入服务时间:");
scanf("%d",&a[i].servetime);
a[i].st1=a[i].servetime;
}
for(i=0;i<n;i++)
for(j=i+1;j<n;j++) //按照各进程到达时间升序,对进程排序 注意:稳定的排序
{
if(a[j].arrivetime<a[i].arrivetime)
{
t=a[j];
a[j]=a[i];
a[i]=t;
}
}
for(i=0;i<n;i++)
printf("***排序后的***%12c%15d%11d%11d:\n",a[i].name,a[i].arrivetime,a[i].servetime,a[i].st1);
int time1=a[0].arrivetime; //当前时间的初值
int flag=1;
int sum=0; //记录完成的进程数
int z=1; //记录第几次调度进程
printf("\n第几次调度进程 运行的进程名 开始运行时间 运行时间 剩余服务时间 结束时间\n");
while(sum<n)
{
flag=0; //标志就绪队列中是否还有进程
for(i=0;i<n;i++) //时间片轮转法执行各进程
{ if(a[i].sc==1)continue; //已完成的进程
else
{ if(a[i].st1<=T && time1>=a[i].arrivetime)//未完成的进程但是还需服务的时间少于等于一个时间片
{ flag=1;
time1=time1+a[i].st1;
a[i].sc=1;
a[i].finishtime=time1;
printf("%8d%12c%15d%11d%11d%11d\n",z++,a[i].name,time1-a[i].st1,a[i].st1,0,time1);
a[i].st1=0;
}
else if( a[i].st1>T && time1>=a[i].arrivetime)//未完成的进程但其还需服务时间至少大于一个时间片
{ flag=1;
time1=time1+T;
a[i].st1-=T;
printf("%8d%12c%15d%11d%11d%11d\n",z++,a[i].name,time1-T,T,a[i].st1,time1);
}
if( a[i].sc==1)sum++; //一个进程执行完就+1
}
}
if(flag==0 && sum<n) // 还有没执行的进程,且没进入就就绪队列
for(i=0;i<n;i++)
if( a[i].sc==0) { time1=a[ i].arrivetime; break;}
}
for(i=0;i<n;i++)
{ a[i].roundtime=(float)(a[i].finishtime - a[i].arrivetime);
a[i].daiquantime=a[i].roundtime / a[i].servetime;
}
Sleep(1000);
tjxx(n);
}
//信息输入
int info()
{ int n = 0;
srand(time(NULL)); //初始化随机函数
printf("请输入需要的进程数:");
scanf("%d", &n);
printf("\n");
for (int i = 0; i < n; i++)
{ printf("进程 %d\t名称:", i+1);
scanf("%s", &a[i].name);
a[i].arrivetime = (rand() % 5 + 1);//随机获取进程运行到达时间
a[i].servetime = (rand() % 5 + 1);//随机获取进程运行服务时间
}
system("cls");
return n;
}
int info1()
{ int n;
printf("请输入需要的进程数:");
scanf("%d", &n);
printf("\n");
return n;
}
int main()
{
int b=1,k,m;
while(b)
{
system("cls");
printf("*************************************************\n");
printf("** **\n");
printf("** 进程调度算法 **\n");
printf("** 程序清单 **\n");
printf("** **\n");
printf("** 1.先来先服务算法 **\n");
printf("** 2.短进程优先算法 **\n");
printf("** 3.时间片轮转算法 **\n");
printf("** 0.退出程序 **\n");
printf("** **\n");
printf("*************************************************\n");
printf("请选择:");
scanf("%d",&k);
switch(k)
{
case 1:fcfs(info());break;
case 2:spf(info());break;
case 3:rr(info1()); break;
case 0:b=0;break;
default:printf("\n*****请输入正确的选择*****\n");
}
if(b!=0)
printf("\n");
system("pause");
}
printf("\n**********谢谢您使用**********\n");
}