文章目录
在学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++;
}
}