进程调度算法(FCFS,SJ,RR)

本文介绍了使用C++实现操作系统中的三种进程调度算法:先来先服务(FCFS)、短进程优先(SJF)和时间片轮转(RR)。通过定义进程类并设置不同的调度策略,展示了如何模拟这些算法的过程,包括对进程状态的管理、时间的计算和进程的排序。代码中还包含了对程序优化的思考,如使用友元函数、自定义类结构和宏定义等。
摘要由CSDN通过智能技术生成

 老师今天上课布置了实验任务,但是班上大家都没有思路,后面老师发布了Java的程序,然后就想用c++实现了一下。

首先就是定义一个进程类。(为了简化,我把数据成员也设置成公有的了)

class process{
public:
	int process_id;//进程名
	int reach_time;//到达时间
	int need_time;//需要时间
	int already_time;//已用CPU时间
	char state[20];//进程状态

	//构造函数
	process(int process_id,int reach_time,int need_time,int already_time,char *state);

};

//先来先服务调度算法FCFS
void FCFS(process *pro,int len);
//短进程优先调度算法SJF
void SJF(process *pro,int len);
//时间片轮转调度算法RR
void RR(process *pro,int len,int time_slice);

 
FCFS( first-come first-served)

先来先服务(FCFS): first come first service)总是把当前处于就绪队列之首的那个进程调度到运行状态。也就说,它只考虑进程进入就绪队列的先后,而不考虑它的下一个CPU的周期的长短及其他因素。

程序思路分析:先来先服务算法是按照到达队列先后的顺序,所以可以先对进程按照达到时间进行升序排序,排在前面的意味着可以先执行,程序后面就是执行顺序了,这个可能出现的是什么情况,就是可能前面的进程执行完了,但是没有新的进程到达,这个显然也是需要计算时间的,所以里面有一个判断,如果进程已经到达了,完成时间就是再加上他需要执行的时间,如果进程还没有达到,那么完成时间就是他开始的时间加上他所需要的时间也就行进程的完成时间(因为之前进程还未达到,所以他不能执行,计算时间应该从他达到时间开始算起)(个人分析,有错误大家可以提)

//先来先服务调度算法FCFS
void FCFS(process *pro,int len){
	//记录完成时间
	int finishtime=pro[0].reach_time;
	int i=0,j=0;
	//按到达时间冒泡
	for(i=0;i<len-1;i++){
		for(j=i;j<len-1;j++){
			if(pro[i].reach_time>pro[j+1].reach_time){
				process tmp=pro[i];
				pro[i]=pro[j+1];
				pro[j+1]=tmp;
			}
		}
	}
	//依次运行进程
	for(i=0;i<len;i++){
		printf("\n此次要执行的pcb的id=%d\n",pro[i].process_id);
		cout<<"执行中..."<<endl;
		strcpy(pro[i].state,"run");
			for(j=0;j<len;j++){//每次运行后各进程的pcb信息
				printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
					pro[j].process_id,pro[j].reach_time,pro[j].need_time,pro[j].already_time,pro[j].state);
		}

		if(finishtime>pro[i].reach_time){//当前进程还未达到
			finishtime=finishtime+pro[i].need_time;
		}else{
			finishtime=pro[i].reach_time+pro[i].need_time;
		}
		pro[i].already_time=pro[i].need_time;
		strcpy(pro[i].state,"finish");
		printf("执行完毕,id=%d,状态转为finish\n",pro[i].process_id);
	}

	printf("\n所以进程执行完毕!\n");
	for(i=0;i<len;i++){
		printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
			pro[i].process_id,pro[i].reach_time,pro[i].need_time,pro[i].already_time,pro[i].state);
	}
}

SJF(short job first)

SJF算法是以作业的长短来计算优先级,作业越短,其优先级越高。作业的长短是以作业所要求的运行时间来衡量的。

程序分析:这个其实和先来先服务是一致的,区别就是前面排序的基准不同,先来先服务是按照达到时间进行排序处理,短作业优先是按照所需要的时间来排序,要说明的是,这里应该是属于非抢占式的短作业优先。


//短进程优先调度算法SJF
void SJF(process *pro,int len){
	//记录完成时间
	int finishtime=pro[0].reach_time;
	int i=0,j=0;
	for(i=0;i<len-1;i++){
		for(j=i;j<len-1;j++){
			//按进程长短冒泡排序
			if(pro[i].need_time>pro[j+1].need_time){
				process tmp=pro[i];
				pro[i]=pro[j+1];
				pro[j+1]=tmp;
			}
		}
	}
	for(i=0;i<len;i++){//依次运行进程
		printf("\n此次要执行的pcb的id=%d\n",pro[i].process_id);
		cout<<"执行中..."<<endl;
		strcpy(pro[i].state,"run");
			for(j=0;j<len;j++){//每次运行后各进程的pcb信息
				printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
					pro[i].process_id,pro[i].reach_time,pro[i].need_time,pro[i].already_time,pro[i].state);
		}
		if(finishtime>pro[i].reach_time){//当前进程还未到达
			finishtime=finishtime+pro[i].need_time;
		}else{
			finishtime=pro[i].reach_time+pro[i].need_time;
		}
		pro[i].already_time=pro[i].need_time;//已使用时间
		strcpy(pro[i].state,"finish");
		printf("执行完毕,id=%d,状态转为finish\n",pro[i].process_id);
	}

	printf("\n所以进程执行完毕!\n");
	for(i=0;i<len;i++){
		printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
			pro[i].process_id,pro[i].reach_time,pro[i].need_time,pro[i].already_time,pro[i].state);
	}
}

RR(round robin)

让就绪队列上的每一个进程每次仅运行一个时间片,采取了非常公平的处理机分配方式.

程序分析:这个就好理解一点就是无论什么情况,就是没一个进程的时间片是一致的,没有运行完的就添加到末尾等待下一次的运行,直到所有的进程都完成就意味着结束。

//时间片轮转调度算法RR
void RR(process *pro,int len){
	//时间片长度
	int time_slice=2;
	int i=0,j=0;
	//按到达时间冒泡
	for(i=0;i<len-1;i++){
		for(j=i;j<len-1;j++){
			if(pro[i].reach_time>pro[j+1].reach_time){
				process tmp=pro[i];
				pro[i]=pro[j+1];
				pro[j+1]=tmp;
			}
		}
	}
	int k=0;//执行的PCB序号
	bool flag=false;
	while(!flag){//标志所有进程还未全部完成
		cout<<endl;
		//判断错误导致找了很久
		//strcmp相同是返回0的,也就是false,如果是直接一个strcmp(pro[k].state,"finish")是刚好不会执行的
		//也就是和理想的相反.
		if(strcmp(pro[k].state,"finish")==0)
			k++;
		printf("此次要执行pcb的id=%d\n",pro[k].process_id);
		printf("执行中...\n");
		strcpy(pro[k].state,"run");
		for(j=0;j<len;j++){//每次运行后各进程的pcb信息
				printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
					pro[j].process_id,pro[j].reach_time,pro[j].need_time,pro[j].already_time,pro[j].state);
		}
		//经历n个时间片需要花费的时间
		pro[k].already_time=pro[k].already_time+time_slice;
		if(pro[k].already_time<pro[k].need_time){//时间片到,还未执行完
			printf("时间片到,还未执行完,id=%d的pcb状态为\"wait\",并调到队列末尾\n",pro[k].process_id);
			strcpy(pro[k].state,"wait");
			process tmp=pro[k];
			for(j=k;j<len-1;j++){//未执行完的插到就绪队列末尾
				pro[j]=pro[j+1];
			}
			pro[len-1]=tmp;
		}else{//时间片后,进程执行完毕
			pro[k].already_time=pro[k].need_time;
			printf("执行完毕,id=%d的PCB状态转为finish",pro[k].process_id);
			strcpy(pro[k].state,"finish");
		}
		for(j=0;j<len;j++){//每次运行后各进程的pcb信息
				printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
					pro[j].process_id,pro[j].reach_time,pro[j].need_time,pro[j].already_time,pro[j].state);
		}
		if(strcmp(pro[len-1].state,"finish")==0)//所有进程结束,退出循环
					flag=true;
	}

然后就是主函数部分.

int main(){
	//process *pro=new process[5];
	process pro[5]={
		process(0,2,8,0,"wait"),
		process(1,5,1,0,"wait"),
		process(2,10,5,0,"wait"),
		process(3,9,9,0,"wait"),
		process(4,3,5,0,"wait")
	};
	int i=0;
	cout<<"初始化后的pcbList:"<<endl;
	for(i=0;i<5;i++){
		printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=%s\n",
					pro[i].process_id,pro[i].reach_time,pro[i].need_time,pro[i].already_time,pro[i].state);
	}

	//先来先服务调度算法FCFS
	//FCFS(pro,5);
	//短进程优先调度算法SJF
	//SJF(pro,5);
	//时间片轮转调度算法RR
	RR(pro,5);

	return 0;

}

记录几个程序遇到的问题:

1.老师给我程序是写在几个文件里面,我是全部都写在一个文件里面,所以一些东西是重复出现的是可以省略的.

2.忘记了友元函数的概念以及自定义类的结构体的概念.

3.轮转调度算法的时间片长度是固定的,可以改良成不是固定的.(这可以通过用户输入,也可以每次程序运行前进行修改)

4.忘记了string类,所以是用字符数组,字符串比较是用strcmp函数,字符串拷贝是用strcpy函数.

5.不同编译器里面的for(int i=0;i<5;i++)这种i的定义,一些编译器i需要重复定义,一些编译器不需要,所以我就同意在循环外进行i,j的定义.

6.string类不是C语言的内置数据类型,所以不用用printf+%s进行输出.不会报错,但是也没有输出结果,需要调用string的c_str(这个也不太行,输出是乱码),还是用cout进行输出吧.

7.进程的个数是固定,也不是很灵活,可以通过用户输入得到,还有就是用宏定义定义一个固定的值,修改的时候直接修改宏定义就行了.(我这里采用的是第二种宏定义的方式)

于是就又重新修改.写了一个友元函数专门用来输出.以及一个共有成员函数来设置数据

//按格式进行打印
void printPCB(process *pro ,int len){
	for(int i=0;i<len;i++){
		printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=",
					pro[i].process_id,pro[i].reach_time,pro[i].need_time,pro[i].already_time);
		//用pro[i].state.c_str输出数据不对劲
		cout<<pro[i].state<<endl;
	}
}
//设置进程数据
void process::setProcess(int id,int reach,int need,int already,string tmp){
	process_id=id;
	reach_time=reach;
	need_time=need;
	already_time=already;
	state=tmp;
}

然后其他的部分进行相应的替换,类的成员变量设置成private的.,当RR算法的时间片长度太大,运行结果与FCFS算一直,而时间片长度取1是与SJF算法一直,为0的话,可以自己看程序.FCFS算法是通过达到的时间进行排序,然后依次执行,而SJF算法是按照进程的长短进行排序后依次运行.

#include<iostream>
#include<string>
using namespace std;
//进程个数
#define PROCESS_NUMBER 5
//时间片长度
#define Time_SLICE 2

class process{
private:
	int process_id;//进程名
	int reach_time;//到达时间
	int need_time;//需要时间
	int already_time;//已用CPU时间
	string state;//进程状态
public:
	//构造函数
	process(int process_id,int reach_time,int need_time,int already_time,string state);
	//缺省的构造函数(需要空参或者缺省的构造函数,否则他不给咱申请空间)
	process();
	//设置数据
	void setProcess(int process_id,int reach_time,int need_time,int already_time,string state);
	//按格式打印数据
	friend void printPCB(process *pro,int len);
	//先来先服务调度算法FCFS
	friend void FCFS(process *pro,int len);
	//短进程优先调度算法SJF
	friend void SJF(process *pro,int len);
	//时间片轮转调度算法RR
	friend void RR(process *pro,int len,int time_slice);

};

int main(){
	//process *pro=new process[5];
	/*process pro[processes_Number]={
		process(0,2,8,0,"wait"),
		process(1,5,1,0,"wait"),
		process(2,10,5,0,"wait"),
		process(3,9,9,0,"wait"),
		process(4,3,5,0,"wait")
	};*/
	//定义进程的数组
	process *pro=new process[PROCESS_NUMBER];
	int i=0;
	//对应类成员变量的相关数据
	int id,reach,need,already;
	string state;

	cout<<"请输入进程PCB相关信息:"<<endl;
	//用户输入数据(初始化)
	for(i=0;i<PROCESS_NUMBER;i++){
		cin>>id;//进程名
		cin>>reach;//达到时间
		cin>>need;//运行需要时间
		cin>>already;//占用CPU时间
		cin>>state;//进程状态
		pro[i].setProcess(id,reach,need,already,state);
	}

	
	cout<<"\n初始化后的pcbList:"<<endl;
	printPCB(pro,PROCESS_NUMBER);

	//先来先服务调度算法FCFS
	//FCFS(pro,PROCESS_NUMBER);
	//短进程优先调度算法SJF
	//SJF(pro,PROCESS_NUMBER);
	//时间片轮转调度算法RR
	RR(pro,PROCESS_NUMBER,Time_SLICE);

	return 0;

}

//构造函数
process::process(int id,int reach,int need,int already,string tmp){
	process_id=id;
	reach_time=reach;
	need_time=need;
	already_time=already;
	state=tmp;
}

//空参(什么都没写)
process::process(){

}

//设置进程数据
void process::setProcess(int id,int reach,int need,int already,string tmp){
	process_id=id;
	reach_time=reach;
	need_time=need;
	already_time=already;
	state=tmp;
}

//按格式进行打印
void printPCB(process *pro ,int len){
	for(int i=0;i<len;i++){
		printf("id=%d,到达时间=%d,需要时间=%d,已使用时间=%d,状态=",
					pro[i].process_id,pro[i].reach_time,pro[i].need_time,pro[i].already_time);
		//用pro[i].state.c_str输出数据不对劲
		cout<<pro[i].state<<endl;
	}
}

//先来先服务调度算法FCFS
void FCFS(process *pro,int len){
	//记录完成时间
	int finishtime=pro[0].reach_time;
	int i=0,j=0;
	//按到达时间冒泡
	for(i=0;i<len-1;i++){
		for(j=i;j<len-1;j++){
			if(pro[i].reach_time>pro[j+1].reach_time){
				process tmp=pro[i];
				pro[i]=pro[j+1];
				pro[j+1]=tmp;
			}
		}
	}
	//依次运行进程
	for(i=0;i<len;i++){
		printf("\n此次要执行的pcb的id=%d\n",pro[i].process_id);
		cout<<"执行中..."<<endl;
		//strcpy(pro[i].state,"run");
		pro[i].state="run";

		//每次运行后各进程的pcb信息
		printPCB(pro,len);
		
		if(finishtime>pro[i].reach_time){//当前进程还未达到
			finishtime=finishtime+pro[i].need_time;
		}else{
			finishtime=pro[i].reach_time+pro[i].need_time;
		}
		pro[i].already_time=pro[i].need_time;
		pro[i].state="finish";
		//strcpy(pro[i].state,"finish");
		printf("执行完毕,id=%d,状态转为finish\n",pro[i].process_id);
	}

	printf("\n所以进程执行完毕!\n");
	printPCB(pro,len);
}


//短进程优先调度算法SJF
void SJF(process *pro,int len){
	//记录完成时间
	int finishtime=pro[0].reach_time;
	int i=0,j=0;
	//冒泡排序
	for(i=0;i<len-1;i++){
		for(j=i;j<len-1;j++){
			//按进程长短冒泡排序
			if(pro[i].need_time>pro[j+1].need_time){
				process tmp=pro[i];
				pro[i]=pro[j+1];
				pro[j+1]=tmp;
			}
		}
	}
	for(i=0;i<len;i++){//依次运行进程
		printf("\n此次要执行的pcb的id=%d\n",pro[i].process_id);
		cout<<"执行中..."<<endl;
		//strcpy(pro[i].state,"run");
		pro[i].state="run";

		//每次运行后各进程的pcb信息
		printPCB(pro,len);
		
		if(finishtime>pro[i].reach_time){//当前进程还未到达
			finishtime=finishtime+pro[i].need_time;
		}else{
			finishtime=pro[i].reach_time+pro[i].need_time;
		}
		pro[i].already_time=pro[i].need_time;//已使用时间
		//strcpy(pro[i].state,"finish");
		pro[i].state="finish";
		printf("执行完毕,id=%d,状态转为finish\n",pro[i].process_id);
	}

	printf("\n所以进程执行完毕!\n");
	//每次运行后各进程的pcb信息
	printPCB(pro,len);
}

//时间片轮转调度算法RR
void RR(process *pro,int len,int time_slice){
	//时间片为0直接退出程序,不然会陷入死循环
	if(time_slice==0){
		cout<<"\n时间片长度不能设置为0哦,不要乱搞,请重新设置"<<endl;
		return;
	}
	int i=0,j=0;
	//按到达时间冒泡
	for(i=0;i<len-1;i++){
		for(j=i;j<len-1;j++){
			if(pro[i].reach_time>pro[j+1].reach_time){
				process tmp=pro[i];
				pro[i]=pro[j+1];
				pro[j+1]=tmp;
			}
		}
	}
	int k=0;//执行的PCB序号
	bool flag=false;
	while(!flag){//标志所有进程还未全部完成
		cout<<endl;
		//判断错误导致找了很久
		//strcmp相同是返回0的,也就是false,如果是直接一个strcmp(pro[k].state,"finish")是刚好不会执行的
		//也就是和理想的相反.
		/*if(strcmp(pro[k].state,"finish")==0)
			k++;*/
		if(pro[k].state=="finish"){
			k++;
		}
		printf("此次要执行pcb的id=%d\n",pro[k].process_id);
		printf("执行中...\n");
		//strcpy(pro[k].state,"run");
		pro[k].state="run";
		//每次运行后各进程的pcb信息
		printPCB(pro,len);

		//经历n个时间片需要花费的时间
		pro[k].already_time=pro[k].already_time+time_slice;
		if(pro[k].already_time<pro[k].need_time){//时间片到,还未执行完
			printf("时间片到,还未执行完,id=%d的pcb状态为\"wait\",并调到队列末尾\n",pro[k].process_id);
			//strcpy(pro[k].state,"wait");
			pro[k].state="wait";
			process tmp=pro[k];
			for(j=k;j<len-1;j++){//未执行完的插到就绪队列末尾
				pro[j]=pro[j+1];
			}
			pro[len-1]=tmp;
		}else{//时间片后,进程执行完毕
			pro[k].already_time=pro[k].need_time;
			printf("执行完毕,id=%d的PCB状态转为finish\n",pro[k].process_id);
			pro[k].state="finish";
			//strcpy(pro[k].state,"finish");
		}
		//每次运行后各进程的pcb信息
		printPCB(pro,len);

		/*if(strcmp(pro[len-1].state,"finish")==0)//所有进程结束,退出循环
					flag=true;*/
		if(pro[len-1].state=="finish"){
			flag=true;
		}
	}
}

写程序当然是需要解决实际问题啦.然后看一下这个题目.

操作系统-------进程和线程调度算法+调度算法的评价指标(周转时间,等待时间等等)_进程在就绪队列中的等待时间_ZJE_ANDY的博客-CSDN博客https://blog.csdn.net/u014453898/article/details/108707528

 要注意一下这里的进程数量是四个,所以就是需要在使用前改一下进程的数量,把宏定义的5改成4.

 那就到这为止了,谢谢大家,希望对大家能够有帮助.

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

封奚泽优

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值