实习报告——进程调度
一. 设计目的
进程管理是操作系统中的重要功能,用来创建进程、撤消进程、实现进程状态转换,它提供了在可运行的进程之间复用CPU的方法。在进程管理中,进程调度是核心,因为在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态,当就绪进程个数大于处理器数目时,就必须依照某种策略决定哪些进程优先占用处理器。本设计模拟在单处理器情况下的进程调度,目的是加深对进程调度工作的理解,掌握不同调度算法的优缺点。
二. 设计内容
设计程序模拟单处理机系统中的进程调度算法,在短作业优先调度算法、时间片轮转调度两种算法实现。
三. 开发环境
VC++6.0平台。
四. 分析设计
<一>.实验原理
短作业优先调度算法是根据作业提出的运行时间的长度来安排调度顺序,最短的作业最先被调度进入执行状态,这是一种照顾短作业的方法,它降低短作业的带权周转时间,却提高了长作业的带权周转时间。对整个系统来说,短作业优先算法可以提高系统的吞吐能力,加快系统的响应时间。但考虑在响应时间上的公平,短作业虽然有短的响应时间,但长作业也有过长的等待时间。
时间片轮转调度算法将所有的就绪进程按到达的先后顺序排队,每个进程被逐一分配一个时间片运行,时间片完毕时运行态进程重新进入就绪队列。进程在执行时分为两种情况,一种是在该时间片内进程执行完毕,这种情况只需调度程序,把该进程弹出队列,并把CPU分配给新的队首。第二种就是在该时间片内进程未执行完毕,则把该进程插入到适合它的位置。
<二>程序结构
短作业优先的程序结构:
包括以下函数:
void input(PCB *a,int n)//输入pcb信息函数
void sort(PCB *a,int n)//短进程排序函数
int run(PCB *a,int n)//计算周转时间与带权周转时间函数
int print(PCB *a,int n)//进程的基本信息打印函数
void STY(PCB *a,int n)//计算平均周转时间和平均带权周转时间函数
zuiduanyyouxian()//最短进程优先调用函数
通过void input() 函数 输入 进程的基本信息之后,下一步执行void sort()函数给输入的进程做一个服务(运行)时间上的排序,排序完成直接进入int run(PCB *a,int n)函数计算每一个进程的周转时间与带权周转时间函数,下一步执行int print(PCB *a,int n)进程的基本信息打印函数将每个进程基本信息输出,最后通过void STY(PCB *a,int n)调用void sort(),int run(PCB *a,int n),int print(PCB *a,int n)总体实现短进程优先算法。
时间片轮转法的程序结构:
时间片轮转法包括以下函数:
Queue *init()进程队列置空,即把队列初始化
int empty(Queue *head)检验队列是否为空函数
Queue *APP(Queue *head,char c[M],int a,int r,char s)(进程队列入队,往后插入)队列入队插入函数
Queue *Creat(Queue *head)创建进程队列函数
void print(Queue *head)输入创建的进程函数
void RUN(Queue *head,int q)时间片轮转调度法函数
void shijianpianlunzhuan()调用时间片轮转法函数
程序执行首先通过Queue *init()把进程队列置空,即把队列初始化,然后执行Queue *Creat(Queue *head)创建进程队列函数,之后便执行void print(Queue *head)输入创建的进程函数,最后执行
void RUN(Queue *head,int q)时间片轮转调度法函数。
<三>数据结构
短作业优先的数据结构:
#define M 100
typedef struct PCB{
char name[M];//进程名称
float arrivaltime;//到达时间
float strartime;//开始运行时间
float finishtime;//结束运行时间
float servicetime;//服务时间
float wholetime;//固定运行时间
float zhouzhuantime;//周转时间
float daiquanzhouzhuantime;//带权周转时间
char state;//运行后的状态
struct PCB *next;//定义一个结构体指针
}PCB;
时间片轮转法的数据结构:
typedef struct PCB{
char name[M];//进程名称
float arrivaltime;//到达时间
float strartime;//开始运行时间
float finishtime;//结束运行时间
float servicetime;//服务时间
float wholetime;//固定运行时间
float zhouzhuantime;//周转时间
float daiquanzhouzhuantime;//带权周转时间
char state;//运行后的状态
struct PCB *next;//定义一个结构体指针
}PCB;
//全局变量
int N;//实际进程数
typedef struct//定义队列
{
PCB *front;//队首指针
PCB *rear;//队尾指针
}Queue
<四>附源程序:
#include<iostream>
#include <cstdlib>
#include <iomanip>
#include<string>
using namespace std;
#define M 100
typedef struct PCB{
char name[M];//进程名称
float arrivaltime;//到达时间
float strartime;//开始运行时间
float finishtime;//结束运行时间
float servicetime;//服务时间
float wholetime;//固定运行时间
float zhouzhuantime;//周转时间
float daiquanzhouzhuantime;//带权周转时间
char state;//运行后的状态
struct PCB *next;//定义一个结构体指针
}PCB;
//全局变量
int N;//实际进程数
float SumWT;//周转时间总和
float SumWWt;//带权周转时间总和
float AverageWT;//平均周转时间
float AvergeWWT;//平均带权周转时间
/**************************************最短优先法*****************************************/
//输入
void input(PCB *a,int n)
{
int i;
cout<<endl;
cout<<"请输入进程的 名字 到达时间 服务时间: (例如: a 0 100)"<<endl;
for(i=0;i<=n-1;i++)
{
cout<<"请输入进程"<<i+1<<"的信息";
cin>>a[i].name;
cin>>a[i].arrivaltime;
cin>>a[i].servicetime;
}
}
//排序过程实现
void sort(PCB *a,int n)
{
int i;
int j;
int m;
int q;
int N;
int k;
int next;
float min;
PCB t;
PCB s;
for(i=0;i<n-1;i++)
for(j=i+1;j<=n-1;j++)
{
if(a[i].arrivaltime>a[j].arrivaltime)
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
//计算完成时间
for(m=0;m<n-1;m++)
{
if(m==0)
{ a[m].finishtime=a[m].arrivaltime+a[m].servicetime;}
else
{a[m].finishtime=a[m-1].finishtime+a[m].servicetime;}
//查找当前进程执行过程中进入系统的时间,统计等待状态进程有多少个
q=0;
for(N=m+1;N<=n-1;N++)
{
if(a[N].arrivaltime<=a[m].finishtime)
q++;
}
//选择最短的进程进入就绪状态再执行
min=a[m+1].servicetime;//m+1=N
next=m+1;
for(k=m+2;k<=m+q;k++)
{
if(a[k].servicetime<min)
{
min=next;
min=a[k].servicetime;
next=a[k].servicetime;
}
s=a[m+1];
a[m+1]=a[next];
a[next]=s;
}
}
}
//进程由就绪状态改为运行状态,并计算周转时间和带权周转时间
int run(PCB *a,int n)
{
int k;
for(k=0;k<=n-1;k++)
{
if(k==0)
{
a[k].strartime=a[k].arrivaltime;
a[k].finishtime=a[k].strartime+a[k].servicetime;
}
else
{
a[k].strartime=a[k-1].arrivaltime;
a[k].finishtime=a[k-1].strartime+a[k].servicetime;
}
}
for(k=0;k<=n-1;k++)
{
a[k].zhouzhuantime=a[k].finishtime-a[k].arrivaltime;
a[k].daiquanzhouzhuantime=a[k].zhouzhuantime/a[k].servicetime;
}
return 0;
}
// 显示
int print(PCB *a,int n)
{
int k;
cout<<"调用最短进程优先算法的运行顺序为:";
cout<<a[0].name;
for(k=1;k<n;k++)
{
cout<<"----------->";
cout<<a[k].name;
}
cout<<endl;
cout<<"具体进程调度信息"<<endl;
cout <<"进程名 到达时间 开始运行时间 结束运行时间 服务时间 周转时间 带权周转时间"<<endl;
for(k=0;k<=n-1;k++){
cout<<setw(4)<<a[k].name
<<setw(10)<<a[k].arrivaltime
<<setw(15)<<a[k].strartime
<<setw(15)<<a[k].finishtime
<<setw(15)<<a[k].servicetime
<<setw(15)<<a[k].zhouzhuantime
<<setw(15)<<a[k].daiquanzhouzhuantime<<endl;
}
return 0;
}
void STY(PCB *a,int n)//最短进程优先并计算平均周转时间和平均帯权周转时间
{
int k;
float atime=0;//平均周转时间
float Atime=0;//平均帯权周转时间
sort(a,n);
run(a,n);
print(a,n);
cout<<"计算平均周转时间和平均帯权周转时间"<<endl;
for(k=0;k<=n-1;k++)
{
atime+=a[k].zhouzhuantime;
Atime+=a[k].daiquanzhouzhuantime;
}
atime=atime/n;
Atime=Atime/n;
cout<<"最短进程优先平均周转时间"<<endl;
cout<<atime<<endl;
cout<<"最短进程优先平均帯权周转时间"<<endl;
cout<<Atime<<endl;
}
void zuiduanyyouxian()
{
int n;
PCB b[100];
cout<<endl;
cout<<"采用最短优先法"<<endl;
cout<<endl;
cout<<"请输入进程数"<<endl;
cin>>n;
input(b,n);
STY(b,n);
}
/****************************************时间片轮转法***********************************************************/
typedef struct//定义队列
{
PCB *front;//队首指针
PCB *rear;//队尾指针
}Queue;
Queue *init()//进程队列置空
{
Queue *head;//定义一个队列指针
head=(Queue*)malloc(sizeof(Queue));
head->front=NULL;
head->rear=NULL;
return head;
}
int empty(Queue *head)//检验队列是否为空
{
return(head->front?0:1);
}
Queue *APP(Queue *head,char c[M],int a,int r,char s)//进程队列入队,往后插入
{
PCB *p;
p=(PCB*)malloc(sizeof(PCB));
strcpy(p->name,c);//复制进程名字
p->arrivaltime=a;
p->servicetime=r;
p->wholetime=r;
p->state=s;
//p->finishtime=0;
//p->daiquanzhouzhuantime=0;
//p->zhouzhuantime=0;
p->next=NULL;
if(empty(head))
{
head->front=head->rear=p;
}
else
{
head->rear->next=p;
head->rear=p;
}
return head;
}
Queue *Creat(Queue *head)//创建进程队列
{
char c[M];
char s='R';//进程状态为运行
int a;
int r;
int i;
cout<<"请输入共有几个进程"<<endl;
cin>>N;
for(i=1;i<=N;i++)
{
cout<<"请输入第"<<i<<"的进程"<<endl;
cout<<"请输入进程名称:";
getchar();
gets(c);
cout<<"请输入进程的到达时间:";
cin>>a;
cout<<"请输入进程的服务时间:";
cin>>r;
head=APP(head,c,a,r,s);
}
return head;
}
void print(Queue *head)//输入创建的进程
{
PCB *p;
p=head->front;
if(!p)
{
cout<<"时间片轮转调度队列为空 "<<endl;
}
while(p)
{
cout<<"进程名称 到达时间 服务时间 状态"<<endl;
cout<<setw(4)<<p->name
<<setw(15)<<p->arrivaltime
<<setw(15)<<p->servicetime
<<setw(15)<<p->state<<endl;
p=p->next;
}
}
/***************时间片轮转调度法********************/
void RUN(Queue *head,int q)//qw为时间片的长度
{
int t=head->front->arrivaltime;
int T=head->rear->arrivaltime;
if(head->front->servicetime<q)
{
t=t+head->front->servicetime;
}
else
{
t=t+q;
}
/************进程不为空时才可以进行调度***********/
while(!empty(head))
{
PCB *p1;
PCB *p2;
cout<<"时刻 进程 运行后的状态"<<endl;
/* 第一种情况:当前运行的时间小于最后一个进程到达时间做一下操作 */
while(t<T)
{
p1=head->front;
cout<<setw(4)<<t
<<setw(10)<<p1->name;
p1->servicetime=p1->servicetime-q;
//如果运行时间小于0,则删除队首
if(p1->servicetime<=0)
{
p1->state='C';
cout<<setw(10)<<p1->state<<endl;
p1->finishtime=t;
p1->zhouzhuantime=p1->finishtime-p1->arrivaltime;
p1->daiquanzhouzhuantime=p1->zhouzhuantime/p1->wholetime;
SumWT+=p1->zhouzhuantime;
SumWWt+=p1->daiquanzhouzhuantime;
cout<<"时刻:"<<t<<setw(4)
<<" 进程:"<<p1->name<<setw(4)
<<" 运行结束!"<<endl;
cout<<"进程:"<<p1->name<<setw(4)
<<" 周转时间:"<<p1->zhouzhuantime<<setw(4)
<<" 带权周转时间:"<<p1->daiquanzhouzhuantime<<endl;
head->front=p1->next;
free(p1);
}
//运行时间大于0,向后找位置插入
else
{
cout<<setw(10)<<p1->state<<endl;
p2=p1->next;
while(p2->next&&p2->arrivaltime!=t)
{
p2=p2->next;
}
//此时无新进队列的进程,有两种情况:
//1:不用找位置往后插入
//2:找位置往后插入
if(p2->arrivaltime != t)
{
PCB *p3=p1,*p4;
while(p3->next && p3->arrivaltime<t)
{
p4=p3;
p3=p3->next;
}
if(p3->arrivaltime>t)
{
if(p4!=p1) //p1 插在 p4后,头为 p1->next
{
head->front=p1->next;
p1->next=p4->next;
p4->next=p1;
}
else // 不做操作
{
p4=p3=p2=NULL;
}
}
else
p4=p3=p2=NULL;
}
else
{
head->front=p1->next;
p1->next=p2->next;
p2->next=p1;
}
}
// 时刻变化
if(head->front->servicetime<q)
t=t+head->front->servicetime;
else
t=t+q;
}
/*****第二种情况当前运行进程所需时间大于最后一个进程到达的时间*******************/
while(t>=T)
{
p1=head->front;
cout<<setw(4)<<t
<<setw(10)<<p1->name;
p1->servicetime=p1->servicetime-q;
//当运行时间小于0,删除队首
if(p1->servicetime<=0)
{
p1->state='C';
cout<<setw(10)<<p1->state<<endl;
p1->finishtime=t;
p1->zhouzhuantime=p1->finishtime-p1->arrivaltime;
p1->daiquanzhouzhuantime=p1->zhouzhuantime/p1->wholetime;
SumWT+=p1->zhouzhuantime;
SumWWt+=p1->daiquanzhouzhuantime;
cout<<"时刻:"<<t<<setw(4)
<<" 进程:"<<p1->name<<setw(4)
<<" 运行结束!"<<endl;
cout<<"进程:"<<p1->name<<setw(4)
<<" 周转时间:"<<p1->zhouzhuantime<<setw(4)
<<" 带权周转时间:"<<p1->daiquanzhouzhuantime<<endl;
head->front=p1->next;
free(p1);
}
else//运行时间大于0,直接插在队尾
{
cout<<setw(10)<<p1->state<<endl;
//若原队列只有一个进程,不必往队尾插
if(!p1->next)
{
head->front=p1;
}
//若原队列有多个进程
else
{
head->front=p1->next;
head->rear->next=p1;
head->rear=p1;
p1->next=NULL;
}
}
//时刻变化,若队列为空,则不做改变
if(empty(head))
return;
else
{
if(head->front->servicetime<q)
t=t+head->front->servicetime;
else
t=t+q;
}
}
//第二种情况结束
}
}
void shijianpianlunzhuan()
{
Queue *head;
int q;
head=init();
head=Creat(head);
cout<<"请输入时间片轮转进程队列为:"<<endl;
print(head);
cout<<"请输入时间片轮转调度时间片为"<<endl;
cin>>q;
//时间片轮转调度
RUN(head,q);
AverageWT=SumWT/N;
AvergeWWT=SumWWt/N;
cout<<"平均周转时间为:"<<AverageWT<<",平均带权周转时间: "<< AvergeWWT<<endl;
}
int main()
{
char c='y';//选择判断
while(c=='y')
{
cout<<"最短优先算法"<<endl;
zuiduanyyouxian();
cout<<"输入n选择时间片轮转算法;输入y选择最短优先算法;输入其它结束!"<<endl;
cin>>c;
}
while(c=='n')
{
cout<<"时间片轮转算法"<<endl;
shijianpianlunzhuan();
cout<<"输入n选择时间片轮转算法;输入其它结束!"<<endl;
cin>>c;
}
return 0;
}