草庐IT

【操作系统】最高响应比优先的进程调度算法-C语言(有代码)

KiefaC 2025-06-21 原文

本文章将会介绍最高响应比优先的进程调度算法,并按照以下需求进行实现:

代码在文章最后

  • 由用户输入每个进程的名称、要求运行时间
  • 每一轮调度,计算每个进程的响应比,R = (W+S)/S=1+W/S,W:等待时间,S:预计执行时间
  • 每次调度响应比最高的就绪进程
  • 若某进程“要求运行时间” ==“已运行时间”,则将其状态置为“结束” ,并退出队列 运行程序,显示每次调度时被调度运行的进程名称,以及各进程控制块的动态变化过程

一、什么是最高响应比优先的进程调度算法

         高响应比优先调度算法(Highest Response Ratio Next)是一种对CPU中央控制器响应比的分配的一种算法。HRRN是介于FCFS(先来先服务算法)与SJF(短作业优先算法)之间的折中算法,既考虑作业等待时间又考虑作业运行时间,既照顾短作业又不使长作业等待时间过长,改进了调度性能。该算法使等待时间较长的长作业也能获得执行的机会 但每次调度时都要估算响应比,会消耗较多的CPU时间。

        响应比的计算方法如下所示:

响应比 =(等待时间+要求服务时间)/ 要求服务时间,即RR=(w+s)/s=1+w/s,因此响应比一定是大于等于1的,其中,W:等待时间,S:预计执行时间。

二、进程pcb中必须包含的元素

进程pcb必须包含以下元素,可以更具需求继续扩充:

pcb

进程id

进程需要运行的时间
进程等待时间
进程的响应比
进程状态

三、示例展示

进程队列如下:

进程服务如下:

 执行的顺序如下:

A——>B——>C——>E——>D

四、具体实现

4.1、数据结构

        在代码实现中使用的是链式结构,使得每个进程通过指针连接起来,这样使得在查询最高响应比的进程的时候方便,同时也使得进程的添加更加方便。

4.2、算法核心

        该算法的核心有二,第一个是进程队列的响应比的更新,由于最高响应比优先的进程调度是非抢占式的,所以每个进程在执行完后,进程队列中的进程的等待时间要做响应的调整,并重新计算响应比。第二个是找到进程队列中响应比最高的进程,而找到响应比最高的进程有两种方法,第一种是遍历进程队列的所有进程的响应比找到最大的,该方法的时间复杂度是O(n);第二种是对所有进程进行排序,该方法的时间复杂度至少为n*logn。在作者的实现代码中是使用的第一种方法。

4.3、代码实现

#include <stdio.h>
#include <stdlib.h>

//最高响应比
typedef struct pcb {
	int pid;
	char state;//E为完成,R为正在运行,W为在就绪队列
	int total_time;//需要的时间
	
	double waittime;//等待时间
	double response;//响应比
	int cputime;//已经执行的时间
	int mark;//标志位,用来表示正在执行的进程,1为在cpu,0为不在cpu
	struct pcb* next;
}*proc;


//初始化进程,需要用户输入进程id和需要cpu的时间
proc init_pcb(struct pcb* head,struct pcb* tail,int mark,int* proc_num) {
	int i;
	//防止进程id重复
	//static int pcb_id[20] = { 0 };
	//static int pcb_id_index = 0;
	int numofpcb;
	proc p, tmp;
	printf("please input the number of process:\n");
	scanf("%d", &numofpcb);
	printf("there are %d processes,please input pcb info:\n", numofpcb);
	p = (proc)malloc(sizeof(struct pcb));
	printf("process id:");
	scanf("%d", &p->pid);
	//do {
	  //printf("process id:");
	  //scanf("%d", &p->pid);
	//	if (pcb_id_index != 0) {
	//		for (int i = 0; i < pcb_id_index; i++) {
	//			if (p->pid == pcb_id[i]) {
	//				printf("process id exist!\n");
	//				break;
	//			}
	//		}
	//	}
	//} while (1);
	//pcb_id[pcb_id_index] = p->pid;
	//pcb_id_index++;
	p->response = 1.0;
	printf("cputime required:");
	scanf("%d", &p->total_time);
	p->state = 'W';
	p->cputime = 0;
	p->mark = mark;
	p->waittime = 0;
	
	head = p;

	for (i = numofpcb; i > 1; i--) {
		tmp = p;
		p = (proc)malloc(sizeof(struct pcb));
		printf("process id:");
		scanf("%d", &p->pid);
		p->response = 1.0;
		printf("cputime required:");
		scanf("%d", &p->total_time);
		p->state = 'W';
		p->cputime = 0;
		p->mark = 0;
		p->waittime = 0;
		
		tmp->next = p;
	}
	tail = p;
	p->next = head;
	*proc_num = (*proc_num) + numofpcb;
	return tail;
}


//找到响应比最大的进程,并返回该进程
proc find_max_response(proc node, struct pcb* head,int* proc_num) {
	double maxresponse;
	proc p = head;
	proc tmp = p, res = p;
	
	//在进程队列中找到响应比最大的进程
	tmp = node;
	proc find = head;
	maxresponse = find->response;
	for (int i = 0; i < *proc_num; i++) {
		if (find->response > maxresponse) {
			res = find;
			tmp->mark = 0;
			res->mark = 1;
			tmp = res;
			maxresponse = res->response;
		}
		find = find->next;
	}
	return res;
}



//调整所有进程的响应,正在执行的进程响应不变,重新计算其他进程的响应比
//因为为抢占式的,平且进程队列会将完成的进程从进程队列删除,所以在进程队列中的进程全是需要调整响应比的
void set_all_process_response(proc head,int* proc_num,proc ntodo) {
	proc tmp = head;
	for (int i = 0; i < *proc_num; i++)
	{
		tmp->waittime = tmp->waittime + ntodo->total_time;
		tmp->response = 1 + tmp->waittime / tmp->total_time;
		tmp = tmp->next;
	}
}

//打印进程的pid、waittime、req_time、response
void display(struct pcb* head,int* proc_num) {
	int i;
	proc p = head;
	printf("pid\twait\treq_time\tresponse\n");
	for (i = 0; i < *proc_num; i++) {
		printf("%d\t%.0lf\t%d\t\t%lf\n", p->pid, p->waittime, p->total_time, p->response);
		p = p->next;
	}
	printf("----------------------------------\n");
}

//删除已经执行完成的进程,并返回进程队列的尾指针
proc delete_finished_pro(proc node, struct pcb* head, struct pcb* tail,int* proc_num) {
	if (head == tail) {
		return NULL;
	}
	proc pre = tail;

	for (int i = 0; i < *proc_num; i++) {
		if (pre->next->pid == node->pid) {
			pre->next = node->next;
			tail = pre;
			head = pre->next;
			break;
		}
	}
	//调整进程数量
	(*proc_num)--;
	return tail;
}

//插入新进程,使用init_pcb()函数完成该功能,并将新进程插入到原进程队列
//中得到新进程队列,并返回新进程队列的尾指针
proc insert_proc(int* insertnum,proc head,proc tail,int* proc_num) {
	proc inhead = NULL, intail = NULL;
	intail = init_pcb(inhead, intail, 0,proc_num);
	inhead = intail->next;
	proc tmp = inhead;

	tail->next = inhead;
	tail = intail;
	tail->next = head;
	//*proc_num = (*proc_num) + *insertnum;
	return tail;
}

//用户选择是否插入新进程,返回进程队列的尾指针
proc judg_insert_proc(int* insertnum,proc head,proc tail,int* proc_num) {
	int choice = 0;
	/*proc intail;*/
	printf("insert new processes or not,please input number(1 yes,0 no):");
	scanf("%d", &choice);
	if (choice == 1) {
		if (head == NULL) {
			tail = init_pcb(head, tail, 1, proc_num);
			head = tail->next;
			return tail;
		}
		tail = insert_proc(insertnum, head, tail,proc_num);
	}
	return tail;
}

//基于动态优先级的进程调度算法,找出优先级最大的进程执行,每一个cpu时间片,调整一次
//所有进程的优先级,再重新寻找优先级最高的进程
void priority(struct pcb* head, struct pcb* tail,int* proc_num) {
	int* insertnum = (int*)malloc(sizeof(int));
	proc intail, inhead;
	*insertnum = 0;
	int i, round;
	double maxlevel;
	round = 1;
	proc p = head;
	proc t = tail;
	proc ntodo, nowmark;
	nowmark = p;
	ntodo = p;//response最大的,马上要做的
	maxlevel = p->response;
	for (i = 0; i < *proc_num; i++) {
		p = p->next;
		if (p->response > maxlevel) {
			ntodo = p;
			nowmark->mark = 0;
			ntodo->mark = 1;
			nowmark = ntodo;
			maxlevel = ntodo->response;
		}
	}
	while (ntodo->total_time > ntodo->cputime)
	{
		*insertnum = 0;
		printf("\n* Round %d, Process %d is running\n", round, ntodo->pid);
		round = round + ntodo->total_time;
		ntodo->state = 'E';
		
		set_all_process_response(head,proc_num,ntodo);
		tail = delete_finished_pro(ntodo, head, tail, proc_num);
		if (tail == NULL) {
			head = NULL;
		}
		else
		{
			head = tail->next;
			display(head, proc_num);
		}
		
		printf("\n▲ process %d is finished\n", ntodo->pid);

		if (head == tail&&head==NULL) {
			
			tail = judg_insert_proc(insertnum, head, tail, proc_num);
			if (tail == NULL) {
				printf("over!!!\n");
				return;
			}
			head = tail->next;
		}
		else
		{
			tail= judg_insert_proc(insertnum, head, tail, proc_num);
			head = tail->next;
		}
		

		ntodo = find_max_response(ntodo,head, proc_num);
	}
}

int main() {
	int* proc_num = (int*)malloc(sizeof(int));
	*proc_num = 0;
	int mark = 1, inmark = 0;
	struct pcb* head = NULL, * tail = NULL;
	tail = init_pcb(head, tail,mark,proc_num);
	head = tail->next;
	display(head,proc_num);
	priority(head,tail,proc_num);
	return 0;
}

有关【操作系统】最高响应比优先的进程调度算法-C语言(有代码)的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  3. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  4. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  5. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  6. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  7. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  8. 程序员如何提高代码能力? - 2

    前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

  9. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  10. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

随机推荐