操作系统实验——处理机调度算法(C语言)

目录

实验要求

代码实现

运行结果

代码解析

 

实验要求

1、设定系统中进程数,每一个进程用一个进程控制块表示。

2、输入每个进程的“优先数”和“要求运行时间”。

3、为了调度方便,将进程按给定的优先数从大到小连成就绪队列。用一单元指出队列首进程

4、处理机调度总是选队首进程运行。采用时间片轮转调度算法

5、若要求运行时间为零,则将其状态置为“结束”,且退出队列。

6、运行所设计程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。

2d4a17a8dbd041edbb18dec08012ecab.png

代码实现

#include <stdio.h>
#define maxPCB 1000      //最大同时处理的进程个数
void PrintPCB(int n,int i);
void Sort(int n);
int Updatequeue(int n,int now);
int N;  	//n=N,记录初始进程块的数量 
int x=0;   	//x为已结束的进程数 
//定义一个结构体数组保存各个进程的信息
struct PCB{
	int id;
	//节点携带的数据
	int priority;    //优先级
	int time;    	 //处理机所需时间
	char state[1];   //状态
	char name[2];     //进程名
}PCB[maxPCB];

//初始化
void Init(int n)      
{
	int i;
	for(i=0;i<n;i++)  
	{
		PCB[i].id=i;
		PCB[i].state[0]='R';     //程序开始运行前,默认状态都为就绪态(Ready) 
		sprintf(PCB[i].name,"P%d",i);  //默认按P0-Pn的顺序存入进程名 
		printf("P%d的优先级为:",i);
		scanf("%d",&PCB[i].priority);//输入优先级
		printf("P%d的运行时间为:",i);
		scanf("%d",&PCB[i].time);    //输入运行时间
	}
	Sort(n);
	printf("\n按优先级从大到小进入队列后...\n");
	PrintPCB(n,0);  //打印初始排序后的队列 
}

//结果打印,用于打印结果
void PrintPCB(int n,int i)
{
	int t=n;
	int p;
	int c=n;
	printf("--------------------------------------\n");
	printf("进程名   优先数   要求运行时间   状态\n");
	while(c--)										//	按顺序打印已存在队列 
	{
		printf("  %c%c       %d\t      %d       \t   %c\t\n",PCB[i].name[0],PCB[i].name[1],PCB[i].priority,PCB[i].time,PCB[i].state[0]);
		i++;
		if(i==t) i=0;//计数满,清零 
	}
	printf("--------------------------------------\n");
	for(p=0;p<x;p++)								//打印出已经退出队列的进程,方便对比 
	{
		printf("  %c%c       %d\t      %d       \t   %c\t\n",PCB[p+N].name[0],PCB[p+N].name[1],PCB[p+N].priority,PCB[p+N].time,PCB[p+N].state[0]);
	}
	printf("--------------------------------------\n");
}

//选择排序
void Sort(int n)          
{
	int i,j,maxpriority,temp1,temp2;
	for(i=0;i<n;i++)
	{
		maxpriority=PCB[i].priority;
		for(j=i;j<n;j++)
		{
			if(maxpriority<PCB[j].priority)
			{
				
				maxpriority=PCB[j].priority;
				PCB[n]=PCB[i];
				PCB[i]=PCB[j];
				PCB[j]=PCB[n];				
			}
		}
	}
}


int Start(int temp)
{
	static now=0;						//静态变量now,作为指针进行+1轮转,保存上一次运行位置 
	//int temp;
	printf("P%d进程执行中....\n结果为:\n",PCB[now].id);
	PCB[now].time--;  					//执行一次,所需时间减1 
	if(PCB[now].time<=0)	PCB[now].state[0]='E';  //进程结束,置状态位为E,退出队列 
					
	if(PCB[now].time<=0)
	{
		temp=Updatequeue(temp,now);					
		now=0;										//删除队首后,now指针不需要动 
	}else	now++;									//如果没有更新,now指针+1 
	if(now==temp)						//计满清零
	{
		now=0;
	}
	PrintPCB(temp,now); //打印新的队列状态表 
	return temp;
}

//就绪队列更新 
int Updatequeue(int n,int now)
{
	int i;
	PCB[N+x]=PCB[now];
	printf("P%d结束运行,退出就绪队列\n\n",PCB[now].id);
	for(i=now;i<n-1;i++) 
	{
		PCB[i]=PCB[i+1];
	}
	n=n-1;				
	x++;
	return n;
}

//运行状态检查 
int Runcheck(int n)    //检查剩余进程状态位是否为'E',否则返回真 
{
	int i;
	for(i=0;i<n;i++)
	{
		if(PCB[i].state[0]=='R')   
		{
			return 1;
		}
	}
	return 0;
}

//启动函数 
void Run(int n)			
{
	while(Runcheck(n))	//反复检查进程,如果全为'E',则循环结束,算法结束 
	{
		n=Start(n);		//将返回新的进程个数作为实参继续传入函数 
	}
}
int main()
{
	int n;
	printf("请输入进程个数:") ;
	scanf("%d",&n);
	N=n; 
	Init(n);  
	Run(n);
	return 0; 
}

运行结果

程序运行结果如下

b083d2c61ae9400f9e7974491b4abf08.png

 状态位代表进程状态,R为就绪(Ready),E为结束(Exit)

代码解析

定义一个结构体数组用于存放数据(这里也可以使用一个链表来实现)

struct PCB{
	int id;
	//节点携带的数据
	int priority;    //优先级
	int time;    	 //处理机所需时间
	char state[1];   //状态
	char name[2];     //进程名
}PCB[maxPCB];

 初始化函数,提示用户输入并从键盘读入进程信息

void Init(int n)      
{
	int i;
	for(i=0;i<n;i++)  
	{
		PCB[i].id=i;
		PCB[i].state[0]='R';     //程序开始运行前,默认状态都为就绪态(Ready) 
		sprintf(PCB[i].name,"P%d",i);  //默认按P0-Pn的顺序存入进程名 
		printf("P%d的优先级为:",i);
		scanf("%d",&PCB[i].priority);//输入优先级
		printf("P%d的运行时间为:",i);
		scanf("%d",&PCB[i].time);    //输入运行时间
	}
	Sort(n);
	printf("\n按优先级从大到小进入队列后...\n");
	PrintPCB(n,0);  //打印初始排序后的队列 
}

结果打印,传入的两个参数分别为在就绪队列中进程的个数和已退出运行的进程的个数,控制打印次数

void PrintPCB(int n,int i)
{
	int t=n;
	int p;
	int c=n;
	printf("--------------------------------------\n");
	printf("进程名   优先数   要求运行时间   状态\n");
	while(c--)										//	按顺序打印已存在队列 
	{
		printf("  %c%c       %d\t      %d       \t   %c\t\n",PCB[i].name[0],PCB[i].name[1],PCB[i].priority,PCB[i].time,PCB[i].state[0]);
		i++;
		if(i==t) i=0;//计数满,清零 
	}
	printf("--------------------------------------\n");
	for(p=0;p<x;p++)								//打印出已经退出队列的进程,方便对比 
	{
		printf("  %c%c       %d\t      %d       \t   %c\t\n",PCB[p+N].name[0],PCB[p+N].name[1],PCB[p+N].priority,PCB[p+N].time,PCB[p+N].state[0]);
	}
	printf("--------------------------------------\n");
}

对输入的进程按优先级从大到小进行排序,排序完成后进入就绪队列,该函数只执行一次,进程进入队列后就不需要再进行排序了

//选择排序
void Sort(int n)          
{
	int i,j,maxpriority,temp1,temp2;
	for(i=0;i<n;i++)
	{
		maxpriority=PCB[i].priority;
		for(j=i;j<n;j++)
		{
			if(maxpriority<PCB[j].priority)
			{
				
				maxpriority=PCB[j].priority;
				PCB[n]=PCB[i];
				PCB[i]=PCB[j];
				PCB[j]=PCB[n];				
			}
		}
	}
}

核心算法:时间片轮转调度算法的具体实现。now指针指向当前轮转位置,定义为static类型,在重新回到函数时应该紧接着当前轮转位置(否则会出现永远从下标0的那个结构体开始执行,显然是不符合要求的)

int Start(int temp)
{
	static now=0;						//静态变量now,作为指针进行+1轮转,保存上一次运行位置 
	//int temp;
	printf("P%d进程执行中....\n结果为:\n",PCB[now].id);
	PCB[now].time--;  					//执行一次,所需时间减1 
	if(PCB[now].time<=0)	PCB[now].state[0]='E';  //进程结束,置状态位为E,退出队列 
					
	if(PCB[now].time<=0)
	{
		temp=Updatequeue(temp,now);					
		now=0;										//删除队首后,now指针不需要动 
	}else	now++;									//如果没有更新,now指针+1 
	if(now==temp)						//计满清零
	{
		now=0;
	}
	PrintPCB(temp,now); //打印新的队列状态表 
	return temp;
}

 在有进程执行结束时调用,更新当前剩余的就绪队列

//就绪队列更新 
int Updatequeue(int n,int now)
{
	int i;
	PCB[N+x]=PCB[now];
	printf("P%d结束运行,退出就绪队列\n\n",PCB[now].id);
	for(i=now;i<n-1;i++) 
	{
		PCB[i]=PCB[i+1];
	}
	n=n-1;				
	x++;
	return n;
}

检查所有标志位,如果发现R,则调度还未结束,返回1

检查未发现R,说明调度已结束,返回0

//运行状态检查 
int Runcheck(int n)    //检查剩余进程状态位是否为'E',否则返回真 
{
	int i;
	for(i=0;i<n;i++)
	{
		if(PCB[i].state[0]=='R')   
		{
			return 1;
		}
	}
	return 0;
}

 调用算法函数,并不断判断程序是否应该结束zhu

//启动函数 
void Run(int n)			
{
	while(Runcheck(n))	//反复检查进程,如果全为'E',则循环结束,算法结束 
	{
		n=Start(n);		//将返回新的进程个数作为实参继续传入函数 
	}
}
主函数
int main()
{
	int n;
	printf("请输入进程个数:") ;
	scanf("%d",&n);
	N=n; 
	Init(n);  
	Run(n);
	return 0; 
}

感谢阅读~各位有什么好的建议评论或者私信我都可以~有没看懂的地方也可以私信我~

觉得有用的话点个赞再走吧~

 

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2023年12月22日
下一篇 2023年12月22日

相关推荐