操作系统先来先服务(FCFS)调度算法

实验过程

  1. 用高级语言设计PCB结构
1、	用高级语言设计PCB结构

#define WAIT "Wait"//就绪状态 
#define RUN "Run"//运行状态 
#define FINISH "Finish"//完成状态 
#define JOBNUMBER 5 //设置进程测试数为5   
typedef struct JCB {
	char jobName[10];//作业名
	int arriveTime;//到达时间
	int runTime;//需要运行时间
	int startTime;//开始时间
	int endTime;//完成时间
	int turnoverTime;//周转时间
	float useWeightTurnoverTime;//带权周转时间
	char processStatus[10];//进程状态
};
static int currentTime = 0;//当前时间
static int finishNumber = 0;//进程完成数量
char JobArray[JOBNUMBER][10];//存放数组名信息的二元数组
float priority[JOBNUMBER];//存放进程优先级的一元数组

//创建JCB
void createJCB(struct JCB* jcb) {
	freopen("input.txt","r",stdin);
	printf("从文件中读入三个参数的数据:\n");
	printf("作业号 到达时间 需要运行时间\n");
	for(int i = 0; i < 5; i++) {
		scanf("%s", &jcb[i].jobName);//作业号
		scanf("%d", &jcb[i].arriveTime);//到达时间
		scanf("%d", &jcb[i].runTime);//需要运行时间
		jcb[i].startTime = 0;
		jcb[i].endTime = 0;
		jcb[i].turnoverTime = 0;
		jcb[i].useWeightTurnoverTime = 0.0;
		strcpy(jcb[i].processStatus, WAIT);
		printf("%s\t%d\t%d\n",jcb[i].jobName, jcb[i].arriveTime,jcb[i].runTime);
	}
	printf("---------------------------------------------\n");
	freopen("CON", "r", stdin);
}



2、	建立进程就绪队列

//打印就绪队列
void printJob(struct JCB* jcb) {
	printf("当前时间为%d\n", currentTime);
	printf("作业号 到达时间 需要运行时间 开始时间 完成时间 周转时间 带权周转时间 进程状态\n");
	for(int i = 0; i < JOBNUMBER; i++) {
		if(strcmp(jcb[i].processStatus, FINISH) == 0)//如果进程为finish状态,这样输出
			printf("%s\t%d\t%4d\t\t%d\t%d\t  %d\t  %.2f\t     %s\n", jcb[i].jobName, jcb[i].arriveTime, jcb[i].runTime, jcb[i].startTime, jcb[i].endTime, jcb[i].turnoverTime, jcb[i].useWeightTurnoverTime, jcb[i].processStatus);
		else if(strcmp(jcb[i].processStatus, RUN) == 0)//如果进程为run状态,这样输出
			printf("%s\t%d\t%4d\t\t%d\t运行中\t  none\t  none       %s\n", jcb[i].jobName, jcb[i].arriveTime, jcb[i].runTime, jcb[i].startTime, jcb[i].processStatus);
		else //如果进程为wait状态,这样输出
			printf("%s\t%d\t%4d\t\t未运行\tnone\t  none\t  none       %s\n", jcb[i].jobName, jcb[i].arriveTime, jcb[i].runTime, jcb[i].processStatus);
	}
	printf("---------------------------------------------\n");
}

//计算平均带权周转时间
float weightTurnoverTimeCount(struct JCB* jcb) {
	float sum = 0.0;
	for(int i = 0; i < JOBNUMBER; i++)
		sum += jcb[i].useWeightTurnoverTime;
	return sum / JOBNUMBER;
}

//计算平均周转时间
float turnOverTimeCount(struct JCB* jcb) {
	float sum = 0.0;
	for(int i = 0; i < JOBNUMBER; i++)
		sum += jcb[i].turnoverTime;
	return sum / JOBNUMBER;
}

//比较各个进程之间的到达时间,按升序排列
void compare(struct JCB* jcb) {
	for(int i = 0; i < JOBNUMBER; i++) {
		int min = jcb[i].arriveTime, minIndex = i;
		for(int j = i + 1; j < JOBNUMBER; j++) {
			if(jcb[j].arriveTime < min) {
				min = jcb[j].arriveTime;
				minIndex = j;
			}
		}
		struct JCB temp = jcb[i];
		jcb[i] = jcb[minIndex];
		jcb[minIndex] = temp;
	}
}

3、编制先来先服务调度算法进程调度算法 

//先来先服务调度算法
void firstComeFirstServed(struct JCB* jcb){
	createJCB(jcb);
	compare(jcb);
	int i = 0;
	//进程调度currentTime每次加1,直到进程全部被调度完成为止
	for(; finishNumber != JOBNUMBER; currentTime++){
		if(currentTime < jcb[0].arriveTime)//当前时间小于第一个节点到来时间时,直接打印
			printJob(jcb);
		else{
			strcpy(JobArray[i], jcb[i].jobName);
			loop(jcb, i);
			i++;
		}
	}
	printInfo(jcb);//打印进程调度顺序,平均周转时间及平均带权周转时间
	currentTime = 0;//静态变量当前时间置位
	finishNumber = 0;//静态变量完成进程数量置位
}

//循环遍历部分
void loop(struct JCB* jcb, int i) {
	jcb[i].startTime = currentTime;
	jcb[i].endTime = jcb[i].startTime + jcb[i].runTime;
	jcb[i].turnoverTime = jcb[i].endTime - jcb[i].arriveTime;
	jcb[i].useWeightTurnoverTime = jcb[i].turnoverTime * 1.0 / jcb[i].runTime;
	strcpy(jcb[i].processStatus, RUN);
	while(true) {
		if(currentTime == jcb[i].endTime) {
			strcpy(jcb[i].processStatus, FINISH);
			finishNumber++;
			if(finishNumber == JOBNUMBER)
				printJob(jcb);
			currentTime--;
			break;
		} else {
			printJob(jcb);
			currentTime++;
		}
	}
}

//打印进程调度顺序,平均周转时间及平均带权周转时间
void printInfo(struct JCB* jcb) {
	printf("1、进程调度顺序为:%s -> %s -> %s -> %s -> %s\n", JobArray[0], JobArray[1], JobArray[2], JobArray[3], JobArray[4]);
	printf("2、平均周转时间为:%.2f\n",turnOverTimeCount(jcb));
	printf("3、平均带权周转时间为:%.2f\n", weightTurnoverTimeCount(jcb));
	printf("------------------测试完毕 ---------\n");
}


//主函数
int main() {
	struct JCB jcb[JOBNUMBER];
	printf("******** 先来先服务调度算法 *********           \n");
firstComeFirstServed(jcb);
	system("pause");
	return 0;
}

五、测试/调试及实验结果分析

1、当前时间为0时,模拟系统从外存的后备队列中选取五项作业(A,B,C,D,E)调入内存,并为它们创建进程,分配必要的资源。然后再将新创建的进程排在就绪队列上等待调度,其进程状态为wait状态,如图1所示。

图 1:创建进程

 

2、当前时间为1时,CE到达,但CE先到达,所以根据先来先服务算法,C先开始执行,进程状态由Wait转换为Run如图2所示。

图 2: C先开始执行

 

3、当前时间为3时,C执行完成,进程状态由Run转换为Finish,与此同时,E开始执行,进程状态由Wait转换为Run如图3所示。

图 3: C执行完成与E开始执行

 

4、当前时间为5时,E执行完成,进程状态由Run转换为Finish,与此同时,根据到达时间,D开始执行,进程状态由Wait转换为Run如图4所示。

图 4:E执行完成与D开始执行

 

5、当前时间为6时,D执行完成,进程状态由Run转换为Finish,与此同时,A开始执行,进程状态由Wait转换为Run,如图5所示。

图 5:D执行完成与A开始执行

 

6、当前时间为9时,A执行完成,进程状态由Run转换为Finish,与此同时,B开始执行,进程状态由Wait转换为Run,如图6所示。

图 6:A执行完成与B开始执行

 

7、当前时间为12时,B执行完成,进程状态由Run转换为Finish,如图7所示。

图 7:B执行完成

 

8、所以用先来先服务算法对所示的作业进行进程调度,

进程调度顺序为:C -> E -> D -> A -> B,如图8所示。

图 8:进程调度顺序

                                                     图 10 :导入作业
 

六、实验结论与体会

1、FCFS的特点是什么?它有什么缺点?

特点: 先来先服务。

优点: 公平、算法实现简单。

缺点: 排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好。即,FCFS算法对长作业有利,对短作业不利。

  1. 周转时间 = 作业完成时间 - 作业提交时间

3、平均周转时间 = 各作业周转时间之和 / 作业数

  1. 带权周转时间 = 作业周转时间 / 作业实际运行的时间 =(作业完成时间-作业提交时间)/ 作业实际运行的时间

4、先来先服务算法,一个进程到达后要么在等待,要么在运行。

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值