C语言简单模拟CPU调度算法(FCFS,SJF,HRRF,RR)


在学OS的时候,要写实验报告,就顺手写了一个处理器调度的模拟,考虑到大部分操作系统用的是C语言,所以也用C语言来模拟,本来考虑用多线程模拟的真实一点,但是后来发现因为进程运行时间很难控制,所以就退而求其次, 采用顺序执行的方式再用循环变量的累加来模拟时间,来模拟CP调度。(Ps:不考虑CPU抢占,为了方便代码重用,我把代码写在头文件里面)

一、处理器调度算法简介

1、概念解释

进程: 计算机资源分配的基本单位
作业: 计算机需要完成的一个任务,一般由多个进程组成
周转时间: 进程的结束时间-进程的开始时间
等待时间: 进程的周转时间-进程的实际占用CPU时间
并行: 进程与进程同时执行,如听歌和写博客同时执行,如CPU和DMA同时运行。
并发: 进程与进程在同一个时间段里面运行,如上午先学英语再学高数,如在s时间段内,先执行进程A再执行进程B。

2、产生原因

在计算机运行过程中,每个作业都由大于1个进程组成,而多个作业的进程可能会产生同时想要占用CPU的情况,但是CPU只有一个,如果使得总体的性能最佳,用户的体验感最好,这时候就需要用到CPU调度算法。

3、算法优劣性的指标

资源利用率:

CPU利用率 = C P U 有效工作时间 C P U 总运行时间 \frac {CPU有效工作时间} {CPU总运行时间} CPU总运行时间CPU有效工作时间
CPU总运行时间 = CPU有效工作时间 + CPU空闲等待时间

吞吐率:

单位时间内CPU处理作业的个数

公平性:

确保每个进程都能获得合理的CPU份额和其他资源份额,不会产生 “饥饿现象”

作业周转时间:

同概念解释部分

二、代码总体思路

在这里插入图片描述
上面分别表示进程id,到达时刻,运行时间,优先级
1. 在文件中读取所有进程信息放入PCB_queue
2. 为到达的进程分配内存,并标识地址
3. 如果CPU空闲,则让CPU指向合适的进程地址
4. 如果CPU忙碌,则让CPU继续工作
5. 重复执行上述2-5.
在进程进入内存时进行分配空间,之后只有指针使用权的转移,最后通过PCB_fin队列进行释放内存。

二、先来先服务(First Come First Serve,FCFS)

算法思想
先到达的进程先进行提供CPU服务。
具体代码

//先来先服务算法。
void FCFS(pcb *CPU, pcb* PCB_fin, Queue &PCB_queue, pcb* PCBpool,int count) {
	int now_time = 0;											//设置初始时间
	idList->next = NULL;

	while (true) {
		reset_pinfo(&CPU, PCB_fin, now_time);					//更新CPU运行的进程的状态

		for (int i = 0; i < count; i++) {						//遍历所有进程,将到达的进程加入进程链表
			if (PCBpool[i].reach_time == now_time) {
				enterQueue_pcbs(PCB_queue, PCBpool[i].id, PCBpool[i].reach_time, PCBpool[i].need_time, PCBpool[i].privilege,0);
			}
		}

		//CPU空闲且就绪队列不为空队列
		if (CPU == FREE && (PCB_queue.front->next != TAIL)) {
			if (PCB_queue.front->next == PCB_queue.tail) {
				PCB_queue.tail = PCB_queue.front;				//这个bug找了一天,在CPU的时候,要考虑tail刚好在CPU后面的情况
			}
			CPU = findearlypcb(PCB_queue);
			CPU->next = TAIL;

			List *temp = (List*)malloc(sizeof(List));
			List* p = idList;
			temp->id = CPU->id;
			temp->next = NULL;
			while (p->next != NULL)	p = p->next;
			p->next = temp;
		}

		if (PCB_queue.front->next == TAIL && CPU == NULL) {		//这里假设就绪队列为空就算进程都运行完成
			break;
		}

		for (pcb* i = PCB_queue.front->next; i != TAIL; i = i->next) {//更新就绪队列的等待时间
			i->wait_time++;
		}
		now_time++;
	}
} 

三、短作业优先(Short Job First,SJF)

算法思想
在就绪队列中找到一个执行时间最短的任务交给CPU处理。
代码实现

//短作业优先算法。
void SJF(pcb* CPU, pcb* PCB_fin, Queue& PCB_queue, pcb* PCBpool, int count) {
	int now_time = 0;											//设置初始时间
	idList->next = NULL;

	while (true) {
		reset_pinfo(&CPU, PCB_fin, now_time);					//更新CPU运行的进程的状态

		for (int i = 0; i < count; i++) {						//遍历所有进程,将到达的进程加入进程链表
			if (PCBpool[i].reach_time == now_time) {
				enterQueue_pcbs(PCB_queue, PCBpool[i].id, PCBpool[i].reach_time, PCBpool[i].need_time, PCBpool[i].privilege,0);
			}
		}

		//CPU空闲且就绪队列不为空队列
		if (CPU == FREE && (PCB_queue.front->next != TAIL)) {
			CPU = findminpcb(PCB_queue);
			CPU->next = TAIL;

			List* temp = (List*)malloc(sizeof(List));
			List* p = idList;
			temp->id = CPU->id;
			temp->next = NULL;
			while (p->next != NULL)	p = p->next;
			p->next = temp;
		}

		if (PCB_queue.front->next == TAIL && CPU == NULL) {		//这里假设就绪队列为空就算进程都运行完成
			break;
		}

		for (pcb* i = PCB_queue.front->next; i != TAIL; i = i->next) {//更新就绪队列的等待时间
			i->wait_time++;
		}
		now_time++;
	}
} 

四、高响应比优先(High Response Ratio First,HRRF)

算法思想
每次循环计算就绪队列中的每个进程的响应比(响应比= 等待时间 运行时间 \frac {等待时间} {运行时间} 运行时间等待时间),找到最高的一个进程交给CPU执行。
具体实现

//高响应比优先调度算法(选做)
void HRRF(pcb* CPU, pcb* PCB_fin, Queue& PCB_queue, pcb* PCBpool, int count) {
	int now_time = 0;											//设置初始时间
	idList->next = NULL;

	while (true) {
		reset_pinfo(&CPU, PCB_fin, now_time);					//更新CPU运行的进程的状态

		for (int i = 0; i < count; i++) {						//遍历所有进程,将到达的进程加入进程链表
			if (PCBpool[i].reach_time == now_time) {
				enterQueue_pcbs(PCB_queue, PCBpool[i].id, PCBpool[i].reach_time, PCBpool[i].need_time, PCBpool[i].privilege,0);
			}
		}

		pcb* temp = PCB_queue.front->next;
		while (temp != NULL) {
			temp->excellent = (float)temp->wait_time / (float)temp->need_time;
			temp = temp->next;
		}

		//CPU空闲且就绪队列不为空队列
		if (CPU == FREE && (PCB_queue.front->next != TAIL)) {
			CPU = findHighRes(PCB_queue);
			CPU->next = TAIL;

			List* temp = (List*)malloc(sizeof(List));
			List* p = idList;
			temp->id = CPU->id;
			temp->next = NULL;
			while (p->next != NULL)	p = p->next;
			p->next = temp;
		}

		if (PCB_queue.front->next == TAIL && CPU == NULL) {					//这里假设就绪队列为空就算进程都运行完成
			break;
		}

		for (pcb* i = PCB_queue.front->next; i != TAIL; i = i->next) {		//更新就绪队列的就绪时间
			i->wait_time++;
		}
		now_time++;
	}
}

五、时间片轮转算法(Round-Robin scheduling,RR)

算法思想
通过CPU设置一个固定大小的时间片,在时间片到达时,置时间片为0,将CPU正在运行的进程放入就绪队列尾
具体实现

//时间片轮转调度算法(选做)
int run_time = 1;															//占用CPU运行时间,初始为1是因为考虑调入CPU的时刻也算运行时间

void reset_pinfo_RR(pcb** CPU, pcb* PCB_fin, int& now_time,Queue &PCB_queue) {
	if ((*CPU) == NULL) {
		//CPU上无任何进程
		return;
	}
	if (now_time - (*CPU)->reach_time - (*CPU)->wait_time == (*CPU)->need_time) {
		//程序运行结束,计算参数
		(*CPU)->isreached = FINAL;
		(*CPU)->end_time = now_time;

		pcb* p = PCB_fin;
		while (p->next != NULL) {
			p = p->next;
		}
		p->next = (*CPU);
		(*CPU) = NULL;
		run_time = 1;
	}
	else if(run_time<20){													//时间片设置为20ms
		(*CPU)->isreached = RUN;
		run_time++;
	}
	else {
		enterQueue_pcbs(PCB_queue, (*CPU)->id, (*CPU)->reach_time, (*CPU)->need_time, (*CPU)->privilege,(*CPU)->wait_time);
		(*CPU)->isreached = READY;
		free(*CPU);
		*CPU = NULL;
		run_time = 1;
	}
	return;
}

void RR(pcb* CPU, pcb* PCB_fin, Queue& PCB_queue, pcb* PCBpool, int count) {
	int now_time = 0;														//设置初始时间
	idList->next = NULL;

	while (true) {
		reset_pinfo_RR(&CPU, PCB_fin, now_time,PCB_queue);					//更新CPU运行的进程的状态

		for (int i = 0; i < count; i++) {									//遍历所有进程,将到达的进程加入进程链表
			if (PCBpool[i].reach_time == now_time) {
				enterQueue_pcbs(PCB_queue, PCBpool[i].id, PCBpool[i].reach_time, PCBpool[i].need_time, PCBpool[i].privilege,0);
			}
		}

		//CPU空闲且就绪队列不为空队列
		if (CPU == FREE && (PCB_queue.front->next != TAIL)) {
			if (PCB_queue.front->next == PCB_queue.tail) {
				PCB_queue.tail = PCB_queue.front;							//这个bug找了一天,在CPU的时候,要考虑tail刚好在CPU后面的情况
			}
			CPU = findearlypcb(PCB_queue);
			CPU->next = TAIL;

			List* temp = (List*)malloc(sizeof(List));
			List* p = idList;
			temp->id = CPU->id;
			temp->next = NULL;
			while (p->next != NULL)	p = p->next;
			p->next = temp;
		}

		if (PCB_queue.front->next == TAIL && CPU == NULL) {					//这里假设就绪队列为空就算进程都运行完成
			break;
		}

		for (pcb* i = PCB_queue.front->next; i != TAIL; i = i->next) {		//更新就绪队列的等待时间
			i->wait_time++;
			i->id;
			i->wait_time;
		}
		now_time++;
	}
} 

六、完整项目链接

https://github.com/goforself/CPU-Process-Manage.git

  • 5
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值