先来先服务和高响应比优先调度算法C语言实现

先来先服务和高响应比优先调度算法C语言实现

目录:

1、进程调度与作业调度的区别:

2、单道批处理系统与多道批处理系统的区别:

3、程序设计用到的公式:

4、高响应比优先算法特点:

5、源代码示例:

6、测试用例:

7、运行结果:


1、进程调度与作业调度的区别:

答:(1)作业调度:根据作业控制块(JCB)中的信息,检查系统中的资源是否满足作业对资源的需求,以及按照一定的调度算法,从外存的后备队列中选取某些作业调入内存,并为它们创建进程,分配必要的资源。然后再将新创建的进程排在就绪队列上等待调度。

(2)进程调度:保存当前进程的处理机的现场信息,如程序计数器、多个通用寄存器中的内容等,然后按某种算法从就绪队列中选取一个进程,将其状态转换为运行状态,再把进程控制块内有关处理机现场的信息装入处理器相应的各个寄存器中,把处理器的控制权交予该进程,让它从上次的断点处恢复运行。

(3)进程调度时让某个就绪状态的进程到处理机上运行,而作业调度只是使作业具有了竞争处理机的机会。


2、单道批处理系统与多道批处理系统的区别:

答:(1)单道批处理系统(Simple Batch Processing System):系统对作业的处理是成批进行的,但在内存中始终只保持一道作业。

特点:自动性、顺序性、单道性

主要问题:CPUI/O设备忙闲不均,对计算为主的作业,外设空闲;对I/O为主的作业,CPU空闲。

(2)多道批处理系统(Multiprogrammed Batch Processing System):在内存中同时存放几个作业,宏观上并行运行——都处于运行状态,但都没运行完;微观上串行运行——各作业交替使用CPU

特点:调度性、无序性、多道性

主要问题:①作业平均周转时间长:短作业的周转时间显著增长;

②无交互能力:整个作业完成后或者中间出错时,才与用户交互,不利于调试和修改。


3、程序设计用到的公式:

答:完成时间 = 开始时间 +  需要运行时间

周转时间 = 完成时间 -  到达时间

带权周转时间 = 周转时间 / 需要运行时间

等待时间 = 当前时间 -  到达时间

优先权 = (等待时间 + 需要运行时间) / 需要运行时间

 

4、高响应比优先算法特点:

答:①当等待时间相同时,短进程的优先权高;

②当需要运行时间相同时,作业的优先权又取决于等待时间,相当于先到先服务;

③长作业的优先级可以随着等待时间的增加而提高,因此长作业等待一段时间后仍能得到调度。


5、源代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
 }
 
//打印用途
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;
	}	
}

//打印进程调度顺序,平均周转时间及平均带权周转时间 
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");
}

//两算法共同循环遍历部分 
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 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 highestResponseRatioNext(struct JCB* jcb){
	createJCB(jcb);
	compare(jcb);
	int i = 0, j = 0; 
	for(; finishNumber != JOBNUMBER; currentTime++){
		float maxPriority = 0.0;
		int indexPriority = 0;
		if(currentTime < jcb[0].arriveTime)//当前时间小于第一个节点到来时间时,直接打印 
			printJob(jcb);
		else{
			for(int i = 0; i < JOBNUMBER; i++){
				if(strcmp(jcb[i].processStatus, FINISH) != 0){
					int waitTime = currentTime - jcb[i].arriveTime;
				 	priority[i] = (waitTime + jcb[i].runTime) * 1.0 / jcb[i].runTime;
				 	if(priority[i] > maxPriority){
			 			maxPriority = priority[i];
			 			indexPriority = i;
			 		}
				}			 	
			}
			strcpy(JobArray[j++], jcb[indexPriority].jobName);
			loop(jcb, indexPriority);
		}
	}
	printInfo(jcb);//打印进程调度顺序,平均周转时间及平均带权周转时间 
	currentTime = 0;//当前时间置位
	finishNumber = 0;//完成进程数量置位 
}

//菜单函数
void menu(struct JCB* jcb){
	int input; 
	while(true){
		printf("------------3114005847 邓钦艺-----------------\n");
		printf("|        1、先来先服务调度算法               |\n");
		printf("|        2、响应比高者优先调度算法           |\n");
		printf("|        3、退出                             |\n");
		printf("----------------------------------------------\n");
		printf("请输入序号以继续程序:");
		scanf("%d", &input);
		switch(input){
			case 1:firstComeFirstServed(jcb);
				break;
			case 2:highestResponseRatioNext(jcb);
				break;
			case 3:
				exit(0);
			default:printf("输入有误,请重新输入!!!\n");
				break; 
		}	
	}
} 

//主函数 
int main(){
	struct JCB jcb[JOBNUMBER];
	menu(jcb);
    system("pause");
	return 0;
}

6、测试用例:

说明:其中三个参数分别是作业名称,到达时间以及需要运行时间

图6.1 测试用例

7、运行结果:

1)菜单页面:

 

图7.1 运行结果截图1

2)先到先服务算法调度过程:

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

 

图7.2 运行结果截图2

②当前时间为1时,job5到达,并开始执行,进程状态由wait转换为run;当前时间为3时,job5执行完毕,开始时间1 + 需要运行时间2 =完成时间3,进程状态由run转换为finish。与此同时,job2开始执行,进程状态由wait转换为run

 

图7.3 运行结果截图3

③当前时间为8时,job2执行完毕,进程状态由run转换为finish,与此同时job3开始执行,进程状态由wait转换为run

 

图7.4 运行结果截图4

④当前时间为12时,job3运行完毕,进程状态由run转换为finish,与此同时job4开始执行,进程状态由wait转换为run

 

图7.5 运行结果截图5

⑤当前时间为19时,job4运行完毕,进程状态由run转换为finish,与此同时job1开始执行,进程状态由wait转换为run

 

图7.6 运行结果截图6

⑥当前时间为21时,job5执行完毕,进程状态由run转换为finish,此时五个进程状态全部转换为finish,进程调度算法停止,打印出进程调度顺序,平均周转时间,以及平均带权周转时间。算法调度完毕后回到菜单界面:

 

图7.7 运行结果截图7

3)高响应比优先算法调度过程:

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

当前时间为1时,只有job5到达,并开始执行,进程状态由wait转换为run

当前时间为3时,job5执行完毕,开始时间1 +需要运行时间2 =完成时间3,进程状态由run转换为finish。与此同时,job3开始执行,进程状态由wait转换为run

 

图7.8 运行结果截图8

②当前时间为7时,job3执行完毕,开始时间3 +需要运行时间4  =完成时间7,进程状态由run转换为finish。与此同时,job2开始执行,进程状态由wait转换为run

 

图7.9 运行结果截图9

③当前时间为12时,job2执行完毕,进程状态由run转换为finish,与此同时job1开始执行,进程状态由wait转换为run

 

图7.10 运行结果截图10

④当前时间为14时,job5执行完毕,进程状态由run转换为finish,与此同时job4开始执行,进程状态由wait转换为run

 

图7.11 运行结果截图11

⑤当前时间为21时,job4执行完毕,进程状态由run转换为finish,此时五个进程状态全部转换为finish,进程调度算法停止,打印出进程调度顺序,平均周转时间,以及平均带权周转时间。算法调度完毕后回到菜单界面:

 

图7.12 运行结果截图12

⑥按3退出

 

图7.13 运行结果截图13

(4)对实现高响应比的验证:

优先权 = (等待时间 + 需要运行时间) / 需要运行时间

①当前时间为1时,只有job5到了,那就先运行它,需要运行时间为2,运行到时间3结束,开始调度下一进程;

②当前时间为3时,job5运行完毕,job2job3job4也已经到达,比较三者的优先权:

Job2:(1 + 5/ 5 = 1.2job3:(1 + 4/  4  = 1.25job4:(0 + 7/ 7  = 1,优先权最大为job3,执行它,需要运行时间为4,因此直到时间7结束,开始调度下一进程;

③当前时间为7时,job3运行完毕,此时job2,job4,job1全都已经到达,比较三者的优先权:

Job2:(5 + 5/ 5 = 2job4:(4+ 7/  7  = 1.57job1:(2 + 2/ 2  = 2,优先权最大为job2job1,优先权相同时执行先到的进程,因此执行进程job2,需要运行时间为5,因此直到时间12结束,开始调度下一进程;

④当前时间为12时,job2运行完毕,比较job1job4的优先权:

Job1:(7 + 2/ 2 = 4.5job4:(9 + 7/  7  = 2.29, 优先权最大为job1,执行它,需要运行时间为2,因此直到时间14结束,开始调度下一进程;

⑤当前时间为14时,剩余进程job4,执行它,需要运行时间为7,因此直到时间21结束,此时后备队列中五个进程执行完毕,调度完毕。

验证结果为:job5 >> job3 >> job2 >> job1 >> job4,与程序运行结果一致。

5)二者对比:

先来先服务算法:

 

图7.14 先来先服务算法运行结果

高响应比优先算法:

 

图7.15 高响应比优先算法运行结果

二者在调度顺序上出现了不一致,

在平均周转时间上:先来先服务 > 高响应比优先

在平均带权周转时间上:先来先服务 > 高响应比优先

在这次运行的测试用例中可以看出,二者算法在两项指标性能上,高响应比优先算法要优于先来先服务算法。

首先高响应比优先算法兼顾了等待时间和需要运行时间,其短进程的优先权高,与此同时长作业的优先级可以随着等待时间的增加而提高,因此长作业等待一段时间后仍能得到调度而不会长期得不到服务。而先来先服务算法则很容易导致长作业到来过多时,短作业再到达造成的“饥饿”现象;也避免了短进程优先中存在大量短作业时造成的长作业“饥饿”现象;高响应比算法在优先权相同的时候,执行到达时间早的进程。


已标记关键词 清除标记
相关推荐
实验一 批处理系统的作业调度 1.实验目的 加深对作业概念的理解; 深入了解批处理系统如何组织作业、管理作业和调度作业; 2.实验预备知识 作业的概念; 作业的创建; 作业的调度。 3.实验内容 编写程序完成批处理系统中的作业调度,要求采用响应优先的作业调度算法。实验具体包括:首确定作业控制块的内容,作业控制块的组成方式;然后完成作业调度;最后编写主函数对所作工作进程测试。 4.提示与讲解 操作系统根据允许并行工作的道数和一定的算法从系统中选取若干作业把它们装入主存储器,使它们有机会获得处理器运行,这项工作被称为“作业调度”。实现这部分功能的程序就是“作业调度程序”。 作业调度实现主要有两个问题,一个是如何将系统中的作业组织起来;另一个是如何进行作业调度。 为了将系统中的作业组织起来,需要为每个进入系统的作业建立档案以记录和作业相关的信息,例如作业名、作业所需资源、作业执行时间、作业进入系统的时间、作业信息在存储器中的位置、指向下一个作业控制块的指针等信息。这个记录作业相关信息的数据块称为作业控制块(JCB),并将系统中等待作业调度的作业控制块组织成一个队列,这个队列称为后备队列。一个作业全部信息进入系统后,就为其建立作业控制块,并挂入后备队列。当进行作业调度时,从后备队列中查找选择作业。 由于实验中没有实际作业,作业控制块中的信息内容只使用了实验中需要的数据。作业控制块中首应该包括作业名;其次是作业所需资源,根据需要,实验中只包括需要主存的大小(采用可移动的动态分区方式管理主存,作业大小就是需要主存的大小)、需要打印机的数量和需要磁带机的数量;采用响应比作业调度算法,为了计算响应比,还需要有作业的估计执行时间、作业在系统中的等待时间;另外,指向下一个作业控制块的指针必不可少。
1. 实验目的 调度的实质是操作系统按照某种预定的策略来分配资源。进程调度的目的是分配CPU资源。由于进程调度程序执行的频率很,因此调度算法的好坏直接影响到操作系统的性能。本实验的目的是编程模拟实现几种常用的进程调度算法,通过对几组进程分别使用不同的调度算法,计算进程的平均周转时间和平均带权周转时间,比较各种算法的性能优劣。 2. 实验原理 [1]. 进程调度算法描述 进程调度算法包括服务调度算法、最短作业时间优先(抢占式和非抢占式)、最响应调度算法4种。(每个人必须做FCFS,然后在后面的三种中任选一种,即每个人必须做2种调度算法的模拟。) [2]. 衡量算法性能的参数 计算进程的平均周转时间和平均带权周转时间。 3. 实验内容 (1)编程实现本实验的程序,要求: [1]. 建立进程的进程控制块,进程控制块至少包括: a) 进程名称; b) 进程需要执行时间; c) 进入就绪队列时间; d) 进程执行开始时间 e) 进程执行结束时间 [2]. 编程实现调度算法。 [3]. 进程及相关信息的输入。这些信息可以直接从键盘上输入,也可以从文件读取。 [4]. 时间片与时间流逝的模拟。本实验需要对算法的执行计时,程序应该提供计算时间的方法。一种最简单的方法是使用键盘,比如每敲一次空格代表一个时间片的流逝。另一种方法是使用系统时钟。 [5]. 一组进程序列执行完毕,打印出结果信息。程序需要计算出每个进程的开始执行时间、结束时间、周转时间和带权周转时间,并为整个进程序列计算平均周转时间和平均带权周转时间。程序将计算结果按一定的格式显示在计算机屏幕上或输出到文件中。打印出进程调度顺序图。 [6]. 实现数据在磁盘文件上的存取功能。 (2)对下列就绪进程序列分别使用上面的几种算法进行调度,计算每种算法下的平均周转时间和平均带权周转时间。 进程号 到达时间 要求执行时间 0 0 1 1 1 35 2 2 10 3 3 5 4 6 9 5 7 21 6 9 35 7 11 23 8 12 42 9 13 1 10 14 7 11 20 5 12 23 3 13 24 22 14 25 31
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页