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();
}
经过这次学习,我懂得了,链表设置头指针的好处,以及尾指针的特殊情况要考虑的地方。