【进程调度】模拟进程调度的过程

大笑1.目的和要求

通过这次实验,理解进程调度的过程,进一步掌握进程状态的转变、进程调度的策略,进一步体会多道程序并发执行的特点,并分析具体的调度算法的特点,掌握对系统性能的评价方法。

2.实验内容

阅读教材《计算机操作系统》第二章和第三章,掌握进程管理及调度相关概念和原理。

编写程序模拟实现进程的轮转法调度过程,模拟程序只对PCB进行相应的调度模拟操作,不需要实际程序。假设初始状态为:有n个进程处于就绪状态,有m个进程处于阻塞状态。采用轮转法进程调度算法进行调度(调度过程中,假设处于执行状态的进程不会阻塞),且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。

程序要求如下:

1)输出系统中进程的调度次序;

2)计算CPU利用率。

3.实验环境

Windows操作系统、VC++6.0

C语言

4.实验提示

C语言实现提示:

1)  程序中进程可用PCB表示,其类型描述如下:

   struct  PCB_type

{

     int  pid ;     //进程名

int   state ;    //进程状态

                2——表示“执行”状态

                1——表示“就绪”状态

                0——表示“阻塞”状态

     int  cpu_time ;  //运行需要的CPU时间(需运行的时间片个数)

   }

2)  设置两个队列,将处于“就绪”状态的进程PCB挂在队列ready中;将处于“阻塞”状态的进程PCB挂在队列blocked中。队列类型描述如下:

      struct  QueueNode{

             struct  PCB_type   PCB;

             Struct  QueueNode  *next;

}

并设全程量:

struct  QueueNode  *ready_head=NULL,       //ready队列队首指针

*ready_tail=NULL ,       //ready队列队尾指针

*blocked_head=NULL,    //blocked队列队首指针

*blocked_tail=NULL;     //blocked队列队尾指针

3)设计子程序

      start_state();  //读入假设的数据,设置系统初始状态

dispath();     //模拟调度

      calculate();    //计算CPU利用率

 

 

这个实验花了我两次课的时间,新手程序写出来倒是很快,但是中途出现各种BUG,但是经过坚持不懈的努力最后还是解决了,yeah大笑

 

废话不多说,直接上代码

/*
* 功能:进程调度
* 时间:2014年4月29日14:16:23
* 作者:cutter_point
*/

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<malloc.h>

using namespace std;

struct PCB_type
{
	int pid;		//进程名
	int state;		//进程状态	2--表示"执行"状态	 1--表示"就绪"状态	0--表示"阻塞"状态
	int cpu_time;	//运行需要的cpu时间(需运行的时间片个数)               
};

typedef struct QueueNode			//队列链表
{
	struct PCB_type PCB;
	struct  QueueNode  *next;
}*QueueLink;


//设置全程变量
struct QueueNode	*ready_head=NULL,       //ready队列队首指针
					*ready_tail=NULL ,       //ready队列队尾指针
					*blocked_head=NULL,    //blocked队列队首指针
					*blocked_tail=NULL;     //blocked队列队尾指针


int t;		//定义一个全局变量个时间片系统释放资源,唤醒处于阻塞队列队首的进程

//设置相应的子程序
void start_state()  //读入假设的数据,设置系统初始状态
{
	int i,n,m;				//用来计数循环
	QueueLink p,p1,p2;		//一个节点指针

	printf("输入n个进程处于就绪状态,m个进程处于阻塞状态,且每过t个时间片系统释放资源,唤醒处于阻塞队列队首的进程。");
	scanf("%d,%d,%d",&n,&m,&t);

	//创建链表
	//创建一个节点
	p1=(QueueLink)malloc(sizeof(QueueNode));		//以免ready和blocked指向相同
	p2=(QueueLink)malloc(sizeof(QueueNode));
	p1->next=NULL;
	p2->next=NULL;
	
	//初始化就绪队列全程变量
	ready_head=ready_tail=p1;
	//吧ready队列链表创建好
	for(i=0 ; i<n ; i++)
	{
		p=(QueueLink)malloc(sizeof(QueueNode));
		p->next=NULL;
		p->PCB.state=1;			//进程状态	2--表示"执行"状态	 1--表示"就绪"状态	0--表示"阻塞"状态
		printf("亲!请输入第 %d 个就绪进程的进程名和进程时间:",i+1);
		scanf("%d,%d",&p->PCB.pid,&p->PCB.cpu_time);
	//	cout<<p->PCB.pid<<endl;
		ready_tail->next=p;		//把p加入表尾
		ready_tail=p;			//吧表尾指针指向新的表尾
	}

	//初始化阻塞队列的全程变量
	blocked_head=blocked_tail=p2;
	//吧blocked队列链表创建好
	for(i=0 ; i<m ; i++)
	{
		p=(QueueLink)malloc(sizeof(QueueNode));
		p->next=NULL;
		p->PCB.state=0;	//进程状态	2--表示"执行"状态	 1--表示"就绪"状态	0--表示"阻塞"状态
		printf("亲!请输入第 %d 个阻塞队列的进程名和进程时间:",i+1);
		scanf("%d,%d",&p->PCB.pid,&p->PCB.cpu_time);
	//	cout<<"ddddddddddd"<<endl;
		blocked_tail->next=p;			//吧p加入阻塞队列的表尾
		blocked_tail=p;			//吧表尾指针指向新的表尾
	}

}

float use_cpu=0,unuse_cpu=0;	//use_cpu记录cpu运行时间,unuse_cpu记录CPU空闲时间,x用来计数是否该唤醒阻塞队列了

void dispath( )     //模拟调度
{

	int x=0;

	QueueLink p;			//指针用于指向队列的位置



		while(ready_head!=ready_tail || blocked_head!=blocked_tail)		//判断ready队列或block队列不为空
		{

			if(ready_head!=ready_tail)		//判断就绪队列不为空
			{
				//取出ready队列的队首节点
				p=ready_head->next;
				p->PCB.state=2;		//开始执行
				printf("当前正在执行的PCB名称是:%d   ",p->PCB.pid);
				p->PCB.cpu_time--;		//需要的时间减少,这里是表示每个进程的时间片是1
				use_cpu++;

				if(ready_head->next != ready_tail)		//判断是否只剩下一个节点了
				{
					if(p->PCB.cpu_time > 0)		//判断时间是否够了,程序执行完成
					{
						ready_head->next=p->next;		//吧队首向后移动一位
						//吧原来的队首放到队尾
						ready_tail->next=p;
						ready_tail=p;		//队尾指向新的节点
						p->next=NULL;		//吧队尾重置为空
						p->PCB.state=1;
					}
					else
					{
						//cout<<"sssssssss"<<endl;
						ready_head->next=p->next;
						printf("  进程%d完成  ",p->PCB.pid);
						p->next=NULL;
						free(p);
					}
				}
				else
				{
					if(p->PCB.cpu_time <= 0)
					{
						ready_tail=ready_head;		//链队列为空,头尾连到一起
						printf("  进程%d完成  ",p->PCB.pid);
						p->next=NULL;
						free(p);
					}
					
				}
			}
			else				//进程状态	2--表示"执行"状态	 1--表示"就绪"状态	0--表示"阻塞"状态
			{
				unuse_cpu++;
				printf("时间片轮空一回!         ");
			}

			x++;		//执行过后吧用掉的时间加上,这里每次为一

			if(x==t && blocked_head != blocked_tail)		//到时候向就绪队列送节点,且阻塞队列不为空
			{
				if(blocked_head->next != blocked_tail)
				{
					p=blocked_head->next;
					printf("  唤醒进程%d",p->PCB.pid );

					blocked_head->next=p->next;		//吧阻塞队列头指针指向下一个
					ready_tail->next=p;
					ready_tail=p;		//指向新的队尾
					p->next=NULL;

			//		printf("xxxxxx\n");
				
					x=0;		//把x重新赋值为零
				}
				else		//如果是只剩下最后一个节点
				{
					p=blocked_head->next;
					printf("  唤醒进程%d",p->PCB.pid );

					blocked_tail=blocked_head;		//吧头尾指针指向一起
					ready_tail->next=p;
					ready_tail=p;		//指向新的队尾
					p->next=NULL;

				}
			}
			printf("\n");
		}

}


void calculate()    //计算CPU利用率
{
	float rate;		//CPU利用率

	rate=use_cpu/(use_cpu+unuse_cpu);

	printf("CPU利用率是:%f\n",rate);

}

void main()
{

	start_state();

//	cout<<ready_head->PCB.pid<<endl;

	dispath();

	calculate();

}


 

经过这次学习,我懂得了,链表设置头指针的好处,以及尾指针的特殊情况要考虑的地方。大笑

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
第二题[提示] (1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。进程控制块的格式为: 进程名 指针 要求运行时间 已运行时间 状态 其进程名----作为进程的标识,假设五个进程进程名分别是Q1,Q2,Q3,Q4,Q5。 指针----进程按顺序排成循环队列,用指针指出下一个进程进程控制块首地址,最后一个进程的指针指出第一个进程进程控制块首地址。 要求运行时间----假设进程需要运行的单位时间数。 已运行时间----假设进程已经运行的单位时间数,初始值为“0”。 状态----有两种状态,“就绪”状态和“结束”状态,初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态变为“结束”,用“E”表示。 (2) 每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“要求运行时间”。 把五个进程按顺序排成循环队列,用指针指出队列连接情况。另用一标志单元记录轮到运行的进程。 (3) 处理器调度总是选择标志单元指示的进程运行。由于本实验是模拟处理器调度的功能,所以,对被选进程并不实际启动运行,而是执行: 已运行时间+1 来模拟进程的一次运行,表示进程已经运行过一个单位的时间。 请注意:在实际的系统,当一个进程被选运行时,必须置上该进程可以运行的时间片值,以及恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行满一个时间片。在这里省去了这些工作,仅用“已运行时间+1”来表示进程已经运行满一个时间片。 (4) 进程运行一次后,应把该进程进程控制块的指针值送到标志单元,以指示下一个轮到运行的进程。同时,应判断该进程的要求运行时间与已运行时间,若该进程要求运行时间≠已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应把它的状态修改为“结束”(E)且退出队列。此时,应把该进程进程控制块的指针值送到前面一个进程的指针位置。 (5) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。 (6) 在所设计的称序应有显示或打印语句,能显示或打印每次被选进程进程名以及运行一次后进称对列的变化。 (7) 为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选进程进程名以及进程控制块的动态变化过程
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值