当先锋百科网

首页 1 2 3 4 5 6 7

**

进程调度算法

**

实验目的及内容

设计进程控制块的数据结构PCB,进程控制块可以包含如下信息:进程号、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等;进程的优先数及需要的运行时间可以事先指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。进程的运行时间以时间片为单位进行计算。仿真时,每个时间片可以让cpu暂停1秒(或100ms,可自定义)。每个进程的状态可以是就绪W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。就绪进程获得 CPU后只能运行一个时间片。
要求:对一个非抢占式多道批处理系统采用以下算法的任意两种,实现进程调度,并计算进程的开始执行时间,周转时间,带权周转时间,平均周转时间,平均带权周转时间。

  1. 先来先服务算法
  2. 短进程优先算法
  3. 高响应比优先算法

示例数据如下(也可自定义数据)
进程号 提交时间 执行时间
1 8:00 25分钟
2 8:20 10分钟
3 8:25 20分钟
4 8:30 20分钟
5 8:35 15分钟

实验原理

两个上机任务都是在考虑时间片的基础上考虑两个算法(时间片可以任意设置)。1.先来先服务算法:我使用的是用一个循环模拟CPU的运行,用一个结构体数组来存放各个进程的信息,使用一个链表来存放处于就绪状态的进程,当一个进程被创建完成后,便让该进程插入到当前正在运行进程的前面,当运行到链表的尾部时,将指针重新指到链表的首部;如果有进程已经执行完毕,则将该进程从链表中删除,直到链表为空时,所以进程执行完毕,最后根据进程已被修改的信息计算开始执行时间,周转时间,带权周转时间,平均周转时间,平均带权周转时间。 2. 短进程优先算法:该算法也是使用一个循环来模拟CPU,基本思想:初始时,每个进程的运行的时间片数量为0,每上一个CPU运行,便让时间片加一,当一个进程下CPU时,比较每个进程的运行的时间片数量,选出运行的时间片数量较少的上CPU运行,然后时间片数量一样,则比较长短进程。这可以避免进程饥饿问题。

代码

#include<iostream>
#include<stdlib.h>
#include<time.h>
#include<string>
using namespace std;
/*
进程号、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等
*/
typedef struct PCB{
	int id;//进程号
	int arrive;// 到达时间(相对与8:00)
	int start;//开始执行的时间 
	int end;//结束时间 
	int run;//还需要运行时间
	int cpu;//总共需要运行时间
	char zhu;//进程状态,s表示进程未被创建,就绪 W(Wait)、运行R(Run)、或完成F(Finish)
	int timecounts;//用于记录已经执行了多少个时间片 
}PCB;
//就绪链表
typedef struct LNode{
    PCB data;
	struct LNode *next;	
}LNode,*linkList;
int allcpu = 0;//cpu已经运行fjfj的时间 
int timecpu = 5;//时间片 

//初始化五个 
void In(PCB PCB[],linkList &L){
	L = (LNode *)malloc(sizeof(LNode));
	L->next = NULL;
	PCB[0].id = 1;
	PCB[0].arrive = 0;
	PCB[0].cpu = 25;
	PCB[0].end = 0;
	PCB[0].run = 25;
	PCB[0].start = 0;
	PCB[0].zhu = 's';
	PCB[0].timecounts = 0; 
	PCB[1].id = 2;
	PCB[1].arrive = 20;
	PCB[1].cpu = 10;
	PCB[1].end = 0;
	PCB[1].run = 10;
	PCB[1].start = 0;
	PCB[1].zhu = 's';
	PCB[1].timecounts = 0;
	PCB[2].id = 3;
	PCB[2].arrive = 25;
	PCB[2].cpu = 20;
	PCB[2].end = 0;
	PCB[2].run = 20;
	PCB[2].start = 0;
	PCB[2].zhu = 's';
	PCB[2].timecounts = 0;
	PCB[3].id = 4;
	PCB[3].arrive = 30;
	PCB[3].cpu = 20;
	PCB[3].end = 0;
	PCB[3].run = 20;
	PCB[3].start = 0;
	PCB[3].zhu = 's';
	PCB[3].timecounts = 0;
	PCB[4].id = 5;
	PCB[4].arrive = 35;
	PCB[4].cpu = 15;
	PCB[4].end = 0;
	PCB[4].run = 15;
	PCB[4].start = 0;
	PCB[4].zhu = 's';
	PCB[4].timecounts = 0;
}


//先来先服务
void FIFO(PCB pro[],linkList &L){
	LNode *p;
	if(L->next == NULL){//将第一个到达的进程进入就绪队列 
		p = (LNode *)malloc(sizeof(LNode));
		p->data = pro[0];
		p->data.start = 0;
		p->data.zhu = 'w';
		p->next = L->next;
		L->next = p;
		pro[0].zhu = 'w';
		}
	LNode *pre,*s;
	pre = L;
	s = L->next;
	bool isdelete = false;//用于判断是否有进程出队列 
	while(L->next != NULL){
		//模拟CPU上运行 
		if(s->data.run > timecpu){
			if(s->data.zhu == 'w'){//将第一次开始执行的精选进行标记 
				s->data.start = allcpu;
				s->data.zhu = 'R';
			}
			allcpu +=timecpu;
			s->data.run -= timecpu;
			pro[s->data.id - 1] = s->data;//改变数组里的值 
			
		}else{//改进程将要结束 
			if(s->data.zhu == 'w'){//将第一次开始执行的精选进行标记
				s->data.start = allcpu;
				s->data.zhu = 'R';
			}
			allcpu += s->data.run;
			s->data.run = 0;
			s->data.end = allcpu;
			pre->next = s->next;
			s->data.zhu = 'F';//将进程状态设为结束态,并将进程从队列中删除 
			pro[s->data.id - 1] = s->data;//改变数组里的值 
			free(s); 
			s = pre ->next;
			isdelete = true;
		}	
	//判断哪个进程到达了,将进程放入发到就绪队列中 
	for(int i = 0;i<5;i++){
		if(pro[i].arrive <= allcpu && pro[i].run > 0 && pro[i].zhu == 's'){//放入当前执行进行之前,(相当于队尾) 
			p = (LNode *)malloc(sizeof(LNode));
			p->data = pro[i];
			p->data.zhu = 'w';
			p->next = pre->next;
			pre->next = p;
			pre = p;
			pro[i].zhu = 'w';
		}
	}
	    if(s == NULL){//如果到达队尾(已将一个进程移出队列) 
				pre = L;
				s = L->next;
			}else if(!isdelete){//判断是否有进程出队列 
				if(s->next != NULL){//判断是否到达最后一个节点 
					pre = s;
				    s = pre->next;
				}else{
					pre = L;
				    s = L->next;
				}
				isdelete = false;
			}
			isdelete = false;
	}
} 


//找出要当前要执行的进程,并返回该进程下标 
int Find(PCB pro[]){
	int j = 0;//用于存放当前需要上CPU运行的进程的下标 
	while(pro[j].zhu == 'F'){
		j++;
	}
	for(int i = j + 1;i < 5;i++){
		if(pro[i].zhu != 'F' && pro[i].arrive <= allcpu){
			//先比较哪个的时间片数量少,如果相等再比较长短进程
			if(pro[i].timecounts < pro[j].timecounts){
				j = i;
			}else if(pro[i].run < pro[j].run){
				j = i;
			}
		}
	}
	return j;
} 


//短进程优先算法
void SJF(PCB pro[]){
	allcpu = 0;
	//计算所以进程总的需要的执行时间 
	int sum;
	for(int i = 0;i < 5;i++){
		sum += pro[i].cpu;
	}
	int j;//用于存放当前需要上CPU运行的进程的下标 
	while(allcpu <= sum){
		j = Find(pro);
		if(pro[j].zhu == 's'){//将第一次开始执行的精选进行标记 
			pro[j].start = allcpu;
			pro[j].zhu = 'R';
		}
		//判断该进程执行完该时间片后便结束
		if(pro[j].run > timecpu){
			allcpu += timecpu;
			pro[j].run -= timecpu;
			pro[j].timecounts++;//时间片加一 
		}else{
			allcpu += pro[j].run;
			pro[j].run = 0;
			pro[j].zhu = 'F'; 
			pro[j].end = allcpu;
		}
		}
	}

//计算并打印开始执行时间,周转时间,带权周转时间,平均周转时间,平均带权周转时间
void cap(PCB pro[]){
    cout<<"进程号     始执行时间     周转时间     带权周转时间    "<<endl; 
    //计算并打印开始执行时间,周转时间,带权周转时间,
    for(int i = 0;i < 5;i++){
    	cout<<pro[i].id<<"          8:";
    	cout<<pro[i].start<<"            ";
    	cout<<pro[i].end-pro[i].arrive<<"           ";
    	cout<<(double)(pro[i].end-pro[i].arrive)/(double)pro[i].cpu<<endl;
	}
	//计算平均周转时间
	int count = 0;
	for(int i = 0;i < 5;i++){
		count +=pro[i].end-pro[i].arrive;
	} 
	cout<<"平均周转时间:"<<count/5.0<<endl;
	//计算平均带权周转时间
	double count1 = 0;
	for(int i = 0;i < 5;i++){
		count1 +=(double)(pro[i].end-pro[i].arrive)/(double)pro[i].cpu;
	} 
	cout<<"平均带权周转时间:"<<count1/5.0<<endl;
}
// 打印进程信息
void print(PCB pro[]){
	for(int i = 0;i < 5;i++){
//		cout<<"进程号:  "<< pro[i].id<<"  进程到达时间:  8:"<<pro[i].arrive
//		<<"  进程开始执行时间  "<<pro[i].start<<"  进程运行结束时间: "<<pro[i].end
//		<<"  进程还需要的执行时间: "<<pro[i].run<<endl; 
		cout<<"进程号:  "<< pro[i].id<<"  进程到达时间:  8:"<<pro[i].arrive
		<<"  进程需要的执行时间: "<<pro[i].run<<endl; 
	}
	cout<<endl;
}
//拷贝数组 
void copy(PCB pro1[],PCB pro[]) {
	for(int i = 0;i<5;i++){
		pro1[i] = pro[i];
	}
}
int main(){
	PCB pro[5];
	
	linkList L;
	In(pro,L);
	cout<<"初始时进程信息:"<<endl;
	print(pro);
	PCB pro1[5];
	copy(pro1,pro);
	cout<<"先来先服务算法:"<<endl;
	FIFO(pro,L);
	cap(pro);
	
	
	cout<<"短进程优先算法:"<<endl;
	SJF(pro1);
	cap(pro1);
}

效果

当时间片为9时
在这里插入图片描述
时间片为15时
在这里插入图片描述

时间片为5时

在这里插入图片描述