广州大学操作系统课程设计时间片轮转法实现处理机调度的程序

进程的id,到达时间,运行时间都是随机生成的
需要注意的是:在时间片轮转法中,假设n时刻就绪队列为 头->:‘C’ ‘N’ <-尾,n时刻就绪队列首部的进程C运行一个时间片且C未运行完,下一时刻进程A到达就绪队列,则就绪队列的排序应该是:N A C。也就是说,当前时刻到达的进程应该排在上一时刻没有运行完重新回到就绪队列排队的进程的前面
没有使用标准模板库queue容器(老师不给),sum一开始设置为9,后面改成了5


一、课程设计题目及内容

设计一个按照时间片轮转法实现处理机调度的程序
时间片轮转法实现处理机调度的程序设计提示如下:
(1)假设系统有n个进程,每个进程用一个进程控制块(PCB)来代表。进程控制块的格式如下表所示,且参数意义也相同。

进程控制块格式
进程名
链接指针
到达时间
估计运行时间
进程状态

(2)按照进程到达的先后顺序排成一个循环队列,设一个队首指针指向第一个到达进程的首址。另外再设一个当前运行进程指针,指向当前正运行的进程。
(3)执行处理机调度时,首先选择队首的第一个进程运行。
(4)由于本题目是模拟实验,所以对被选中的进程并不实际启动运行,而只是执行如下操作:
1)估计运行时间减1;
2)输出当前运行进程的名字。
用这两个操作来模拟进程的一次运行。
(5)进程运行一次后,以后的调度则将当前指针依次下移一个位置,指向下一个进程,即调整当前运行指针指向该进程的链接指针所指进程,以指示应运行进程,同时还应判断该进程的剩余运行时间是否为0,若不为0,则等待下一轮的运行,若该进程的剩余运行时间为0,则将该进程的状态置为完成状态“C”,并退出循环队列。
(6)若就绪队列不为空,则重复上述的步骤(4)和(5)直到所有进程都运行完为止。
(7)在所设计的调度程序中,应包含显示或打印语句,以便显示或打印每次选中进程的名称及运行一次后队列的变化情况。

二、实验源代码

代码如下:

#include<iostream>
#include<time.h>
#include<iomanip>
using namespace std;
typedef struct PCB
{
	int name;//进程名(id)
	struct PCB* next;//指针
	int ta;//到达时间
	int tw;//工作时间
	int state;//完成状态(完成为1,未完成为0)
}PCB, * PCBptr;
typedef struct
{
	PCBptr front;
	PCBptr rear;
}LinkQueue;
void print(LinkQueue& Q)
{
	auto p = Q.front->next;
	cout << "name" << setw(6) << "ta" << setw(6) << "tw" << endl;
	while (p != NULL)
	{
		cout << p->name << setw(8) << p->ta << setw(8) << p->tw << endl;
		p = p->next;
	}
}
void InitQueue(LinkQueue& Q)
{
	Q.front = Q.rear = new PCB;
	Q.front->next = NULL;
}
int DeQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear)return 0;
	auto p = Q.front->next;
	Q.front->next = p->next;
	if (Q.rear == p)Q.rear = Q.front;
	delete p;
	return 1;
}

void EnQueue(LinkQueue& Q, PCB e)
{
	PCBptr p;
	p = new PCB;
	p->name = e.name; p->next = e.next; p->state = e.state; p->ta = e.ta; p->tw = e.tw;
	p->next = NULL; Q.rear->next = p;
	Q.rear = p;
}
void EnQueue2(LinkQueue& Q)//对头元素插入队尾
{
	PCBptr p;
	p = new PCB; 
	p->name = Q.front->next->name; p->next = Q.front->next->next; p->state = Q.front->next->state;
	p->ta = Q.front->next->ta; p->tw = Q.front->next->tw;
	p->next = NULL; Q.rear->next = p;
	Q.rear = p;
}
int NOW = 0;
void solve(LinkQueue& Q)
{
	int sum = 5;//一共9个进程
	bool A[9]{ false };//用于随机生成
	PCB P[9];
	//初始化
	int now = 0;
	for (int i = 0; i < sum; i++)
		while (1)
		{
			P[i].name = rand() % sum;
			if (A[P[i].name] == false)
			{
				A[P[i].name] = true;
				if (i == 0)P[i].ta = 0;
				else
				{
					int temp = rand() % 5 + 0;
					P[i].ta = now + temp;
					now = P[i].ta;
				}
				P[i].tw = rand() % 5 + 1;
				P[i].state = 0;//完成状态初始化
				break;
			}
		}
	cout << "进程名" << " " << "到达时间" << " " << "运行时间" << endl;
	for (int i = 0; i < sum; i++)
		cout << P[i].name << setw(10) << P[i].ta << setw(10)<<P[i].tw<<endl;
	int pi = 0, finish = 0,flag=0;

	while (finish < sum)
	{	
		while (pi<sum)
		{
			if (P[pi].ta <= NOW)
				EnQueue(Q, P[pi++]);
			else break;
		}
		if (flag == 1)//上一秒有结点未处理
		{
			EnQueue2(Q);
			DeQueue(Q);
			flag = 0;
		}
		cout << "-------------时间片为:" << NOW << "--------------\n当前的就绪队列为:\n";
		print(Q);
		if (Q.front->next!=NULL)
		{
			auto p = Q.front->next;
			cout << ">>>>当前运行的进程为:"<<p->name << "  //时间片:" <<NOW<< endl;
			p->tw -= 1;
			if (p->tw == 0)
			{
				cout << "进程:" << p->name << " 已完成" << endl;
				finish++; DeQueue(Q);
			}
			else//否则把未完成的结点放到队尾,头指针后移
			{
				if (P[pi].ta == NOW + 1)//pi指到的进程会在下一时刻到达
					flag = 1;
				else
				{
					EnQueue2(Q);
					DeQueue(Q);
				}
			}
			cout << "进程运行完毕" << endl;
		}
		else { cout << "当前无进程运行\n"; }
		NOW++;
	}
}
int main()
{
	srand((int)time(0));
	LinkQueue Q;
	InitQueue(Q);
	solve(Q);
}

三、程序运行时的效果

在这里插入图片描述在这里插入图片描述在这里插入图片描述

四、程序中使用的数据及主要符号说明

typedef struct PCB
{
	int name;//进程名(id)
	struct PCB* next;//指针
	int ta;//到达时间
	int tw;//工作时间
	int state;//完成状态(完成为1,未完成为0)
}PCB, * PCBptr;
typedef struct
{
	PCBptr front;
	PCBptr rear;
}LinkQueue;
int NOW = 0;//记录(调度过程中的)当前的时间
int pi = 0, finish = 0,flag=0;//pi为数组的下标,finish为完成进程的个数,flag作为判断标志

五、功能模块的设计分析及算法描述

1.所需要的数据结构

①一个PCB结构的结构数组(用于存放随机初始化的进程数据)

构造过程:

	int sum = 5;//一共9个进程
	bool A[9]{ false };//用于随机生成
	PCB P[9];
	//初始化
	int now = 0;
	for (int i = 0; i < sum; i++)
		while (1)
		{
			P[i].name = rand() % sum;
			if (A[P[i].name] == false)
			{
				A[P[i].name] = true;
				if (i == 0)P[i].ta = 0;
				else
				{
					int temp = rand() % 5 + 0;
					P[i].ta = now + temp;
					now = P[i].ta;
				}
				P[i].tw = rand() % 5 + 1;
				P[i].state = 0;//完成状态初始化
				break;
			}
		}
②一个就绪队列:

队列的初始化:

void InitQueue(LinkQueue& Q)
{
	Q.front = Q.rear = new PCB;
	Q.front->next = NULL;
}

队列结构如图:
在这里插入图片描述

该数组是先随机生成一个没有生成过的进程id,然后再随机生成它的信息,到达时间的生成为当前时刻+0~5,所以这个数组其实是按到达时间排序的,前面的先到后面的后到。

2.具体的实现过程

①首先有个指向数组PCB P[9]的指针pi,pi指向还没可以进入队列中的进程(到时间才能进入),这个只负责(在第一次时)把进程放入就绪队列,后续的循环操作就是队列负责了。
然后就是要设定一个全局变量int NOW来记录当前的时间(片),初始化为0

①首先判断是否有进程的到达时间刚好等于当前时间(要进入就绪队列了),有就将pi指向的进程放入就绪队列,pi往后移,没有就进行下一步

②就绪队列中头指针指向的结点的运行时间-1,然后判断运行时间是否为0,若为0,调用(队头)出队函数DeQueue,若没有,进行第③步

③此时判断下一个时间片是否有进程要进来,因为pi指的是还没放进去的进程,所以可以根据P[pi].tw?=NOW+1来判断。如果没有,调用Enqueue2函数(将头指针指向的结点放在就绪队列之后,然后更改头指针),如果有,置判断数flag=1,进行下步骤④

④if(flag==1){…}在while循环中的步骤①的后面进行判断。如果flag=1,说明上一步的头结点还没出队(因为要保留信息所以没出),且当前时刻到达的进程已经入队了,所以这个时候可以把头结点移到队伍的后面,然后让这个队头出队。

如果队为空就等于没有进程运行
每一次大循环时间片就+1,所以是以每一时刻的变化来设计的。然后有个int finish来记录完成的进程数,当finish=sum时大循环结束

3.函数使用

队头出队:

int DeQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear)return 0;
	auto p = Q.front->next;
	Q.front->next = p->next;
	if (Q.rear == p)Q.rear = Q.front;
	delete p;
	return 1;
}

两个插入函数都是操作同一个队列
插入函数1(首部加入达到时间=当前时间的进程):

void EnQueue(LinkQueue& Q, PCB e)
{
	PCBptr p;
	p = new PCB;
	p->name = e.name; p->next = e.next; p->state = e.state; p->ta = e.ta; p->tw = e.tw;
	p->next = NULL; Q.rear->next = p;
	Q.rear = p;
}

插入函数2(将还没有运行完但当前时间片用完了的进程重新插入就绪队列的后面):

void EnQueue2(LinkQueue& Q)//对头元素插入队尾
{
	PCBptr p;
	p = new PCB; 
	p->name = Q.front->next->name; p->next = Q.front->next->next; p->state = Q.front->next->state;
	p->ta = Q.front->next->ta; p->tw = Q.front->next->tw;
	p->next = NULL; Q.rear->next = p;
	Q.rear = p;
}

六、实验结果分析,实验收获和体会

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
广州大学操作系统课后的习题zyl主要涉及操作系统的基本概念、功能和特征。学习这些习题可以帮助我们更好地理解操作系统的工作原理和应用场景。 首先,操作系统是计算机系统中的核心软件,它负责管理和控制计算机硬件资源,并为用户和应用程序提供服务。习题zyl中可能会涉及到操作系统的功能,如进程管理、内存管理、文件系统管理等。我们需要学习各个管理模块的基本概念和功能。 其次,操作系统有着不同的特征和分类。习题zyl可能会要求我们了解操作系统的特征,如并发性、共享性、虚拟性、异步性等。我们需要对这些特征有深入的理解,并能够应用到具体的操作系统场景中。 此外,习题可能还会要求我们掌握操作系统的基本概念和术语,如进程、线程、调度算、页表等。这些概念是操作系统的基础,也是我们理解和使用操作系统的前提。 为了更好地完成习题zyl,我们可以采取以下学习方:首先,认真听讲课堂上的操作系统相关知识,掌握基本概念和原理。其次,多做一些操作系统实验和编程练习,提高对操作系统的实际应用能力。最后,多和同学、老师或者在线讨论区交流,共同解决习题中的难题。 通过认真学习和应用,我们将能够更好地掌握操作系统的基本知识和技能,为我们的学业和职业发展打下坚实的基础。同时,操作系统作为计算机科学的重要基础学科,对我们理解计算机原理和技术具有重要作用。因此,我们应该积极投入到操作系统习题的学习中,提高对操作系统的理解和应用水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值