进程调度
进程调度是处理机管理的核心内容。本实验要求编程实现一个简单的进程调度程序。通过本实验可以加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实现方法。
2. 实验平台
操作系统:Windows
注:可使用自己熟悉的语言设计编程,但需在实验报告中注明编译环境以及编辑工具。
3. 实验内容和要求
①设计进程控制块PCB表结构。
②输入一组进程及其相关参数。
③编制进程一个或多个调度算法,可选调度算法有:先来先服务法、短作业优先法、优先级法。
④计算出这组进程的平均周转时间。
4.运行结果
5.运行代码
因为每一次调度算法的时候都会把链表的节点删掉,执行一次调度算法之后,进程链表就会删掉,个人的解决办法是在创建进程链表的时候复制准备多个链表,但是这样会一定程度上造成空间浪费,各位伙伴可以尝试自己优化更好的代码。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef struct node
{
char name; //进程名
int Arrive_Time; //到达时间
int Serve_Time; //服务时间
int Finish_Time; //完成时间
int priority; //优先级
struct node *next; /*pcb define*/
}*PCB;
void ProcessCreate(PCB &head) //创建进程函数
{
char c;
PCB p,q;
head=(PCB)malloc(sizeof(node)); //申请头结点空间
head->next=NULL; //刚开始头结点指向为空
q=head;
cout<<endl;
while(1)
{
p=(PCB)malloc(sizeof(node));
cout<<"请输入进程名称:";
cin>>p->name; //输入进程名称
cout<<"请输入"<<p->name<<"的到达时间:";
cin>>p->Arrive_Time; //输入到达时间
cout<<"请输入"<<p->name<<"的所需服务时间:";
cin>>p->Serve_Time; //输入服务时间
cout<<"请输入"<<p->name<<"的优先级:";
cin>>p->priority; //输入优先级
p->Finish_Time=0; //刚开始完成时间置为空
q->next=p; //连接到链表末尾
q=p;
q->next=NULL; //末尾指向置空
cin.clear(); //清空输入缓存区
cin.sync();
cout<<"还有进程需要输入吗?(Y/N)";
cin>>c;
if(c=='n'||c=='N') //判断是否继续加入进程
break;
if(c=='y'||c=='Y'){
cin.clear(); //清空缓冲区
cin.sync();
}
else{
system("输入错误,请重新输入");
}
}
}
void Create(PCB &head_1) {
head_1=(PCB)malloc(sizeof(node)); //申请头结点空间
head_1->next=NULL; //刚开始头结点指向为空
}
void CopyProcess(PCB &head,PCB &head_1) { //复制相同的链表
PCB temp,p;
p=head->next;
while(p!=NULL){
temp=(PCB)malloc(sizeof(node));
temp->Arrive_Time=p->Arrive_Time;
temp->Finish_Time=p->Finish_Time;
temp->name=p->name;
temp->priority=p->priority;
temp->Serve_Time=p->Serve_Time;
temp->next=head_1->next;
head_1->next=temp;
p=p->next;
}
}
void PCB_View(PCB head) //查看当前所有进程信息函数
{
PCB p;
p=head->next;
if(p==NULL) //为空则表示没有进程,都执行完了
cout<<"当前系统中没有进程!"<<endl;
else
{
cout<<endl<<"进程 到达时间 服务时间 优先级"<<endl; //表头
while(p)
{
cout<<p->name<<"\t "<<p->Arrive_Time<<"\t "<<p->Serve_Time<<"\t "<<p->priority<<endl;
p=p->next; //循环打印进程信息
}
}
}
void PCB_Sort(PCB &head) //将进程按到达时间从小到大排序函数
{
PCB p,q;
char c;
int temp;
p=head->next;
q=head->next;
while((p!=NULL)&&(p->next!=NULL))
for(p=head->next; p->next!=NULL; p=p->next) //冒泡排序
for(q=head->next; q->next!=NULL; q=q->next) //判断进程到达时间是否比后一个进程大
if(q->Arrive_Time>q->next->Arrive_Time)
{
c=q->name; //交换进程名字
q->name=q->next->name;
q->next->name=c;
temp=q->Arrive_Time; //交换到达时间
q->Arrive_Time=q->next->Arrive_Time;
q->next->Arrive_Time=temp;
temp=q->Serve_Time; //交换服务时间
q->Serve_Time=q->next->Serve_Time;
q->next->Serve_Time=temp;
temp=q->Finish_Time; //交换完成时间
q->Finish_Time=q->next->Finish_Time;
q->next->Finish_Time=temp;
temp=q->priority; //交换优先级
q->priority=q->next->priority;
q->next->priority=temp;
}
}
int PCB_Num(PCB &head,int time) //找到当前时间点有多少个进程就绪了
{
int num=0;
PCB p;
p=head->next;
while(p!=NULL&&p->Arrive_Time<=time) //如果到达时间小于等于当前时间则表示已就绪
{
num++;
p=p->next;
}
return num; //返回当前就绪进程个数
}
void PCB_Delet(PCB &head,PCB p) //将执行完的进程从链表中删除
{
PCB q;
q=p->next;
p->next=q->next; //指向当前进程的下一个进程
free(q); //释放进程空间
}
void Process_FCFS(PCB &head) //先来先服务算法函数
{
PCB p,q;
int time=0,num;
float i=0,turn_time=0; //记录总周转时间
cout<<endl<<" 先来先服务法 "<<endl;
cout<<"进程 到达时间 服务时间 优先级 完成时间 周转时间"<<endl; //表头
p=head->next;
while( p!=NULL) //遍历所有进程
{
i++; //记录一共有多少个进程,好计算平均周转
num=PCB_Num(head,time); //得到当前时间点就绪进程个数
if(num==0)
time++; //如果没有进程时间继续往前走
else
{
q=p->next;
time+=p->Serve_Time; //更新当前时间为:当前时间+服务时间
p->Finish_Time=time; //当前时间即为进程完成时间
cout<<p->name<<"\t "<<p->Arrive_Time<<"\t "<<p->Serve_Time<<"\t "
<<p->priority<<"\t "<<p->Finish_Time<<"\t "<<time-p->Arrive_Time<<endl;//输出进程信息
turn_time+=time-p->Arrive_Time; //把周转时间加起来
p=q; //把执行完的进程从链表删除
}
}
turn_time=turn_time/num; //计算平均周转时间
cout<<"平均周转时间为:"<<turn_time<<endl; //输出周转时间
}
PCB Priority_max(PCB &head,int num) //找到就绪进程中优先级最高的进程函数
{
PCB p,q,r;
int flag=0;
p=head->next;
r=p;
q=head->next;
int max;
max=p->priority; //将最高优先级初始化为第一个进程优先级
while(num>0) //遍历就绪进程
{
if(p->priority<max)
{
max=p->priority; //更新最高优先级
r=q; //保存最高优先级进程的前一个结点
flag=1; //标记置 1,说明最小服务时间不为第一个结点
}
num--;
q=p; //保存当前结点
p=p->next; //遍历下一个结点
}
if(flag==0) //表示当前进程链表中第一个进程优先级最高
r=head;
return r; //返回最高优先级进程的前一个结点
}
void Process_Priority(PCB &head) //优先级法函数
{
int time=0,num;
float i=0,turn_time=0; //记录总周转时间
PCB p,q;
cout<<endl<<" 优先级法 "<<endl; //表头
cout<<"进程 到达时间 服务时间 优先级 完成时间 周转时间"<<endl; //表头
while(head->next!=NULL)
{
i++;
num=PCB_Num(head,time); //得到当前时间点就绪进程个数
if(num==0)
time++; //如果没有进程时间继续往前走
else if(num==1)
{
p=head->next;
time+=p->Serve_Time; //更新当前时间为:当前时间+服务时间
p->Finish_Time=time; //当前时间即为进程完成时间
cout<<p->name<<"\t "<<p->Arrive_Time<<"\t "<<p->Serve_Time<<"\t "
<<p->priority<<"\t "<<p->Finish_Time<<"\t "<<time-p->Arrive_Time<<endl; //输出进程信息
turn_time+=time-p->Arrive_Time; //把周转时间加起来
q=head;
PCB_Delet(head,q); //把执行完的进程从链表删除
}
else //就绪队列中不止一个进程,需要比较目录
{
q=Priority_max(head,num); //得到优先级高最高的进程的前驱结点
p=q->next;
time+=p->Serve_Time; //更新当前时间为:当前时间+服务时间
p->Finish_Time=time; //当前时间即为进程完成时间
cout<<p->name<<"\t "<<p->Arrive_Time<<"\t "<<p->Serve_Time<<"\t "
<<p->priority<<"\t "<<p->Finish_Time<<"\t "<<time-p->Arrive_Time<<endl; //输出进程信息
turn_time+=time-p->Arrive_Time; //把周转时间加起来
PCB_Delet(head,q); //把执行完的进程从链表删除
}
}
turn_time=turn_time/i; //计算平均周转时间
cout<<"平均周转时间为:"<<turn_time<<endl; //输出周转时间
}
PCB Serve_Time_min(PCB &head,int num) //找到就绪进程中服务时间最短的进程函数
{
PCB p,q,t;
int min,flag=0;
p=head->next;
q=head->next;
t=head->next;
min=p->Serve_Time; //将最短服务时间初始化为第一个进程时间
while(num>0) //遍历就绪进程
{
num--;
if(p->Serve_Time<min)
{
min=p->Serve_Time; //更新最短服务时间
t=q; //保存最短服务时间进程的前一个结点
flag=1; //标记置 1,说明最小服务时间不为第一个结点
}
q=p; //保存当前结点
p=p->next; //遍历下一个结点
}
if(flag==0) //表示当前进程链表中第一个进程服务时间最短
t=head;
return t; //返回最短服务时间进程的前一个结点
}
void Process_SJF(PCB &head) //短作业优先法的函数
{
int time=0,num;
float i=0,turn_time=0; //记录总周转时间
PCB p,q;
cout<<endl<<" 短作业优先法 "<<endl; //表头
cout<<"进程 到达时间 服务时间 优先级 完成时间 周转时间"<<endl; //表头
while(head->next!=NULL)
{
i++;
num=PCB_Num(head,time); //得到当前时间点就绪进程个数
if(num==0)
time++; //如果没有进程时间继续往前走
else if(num==1) //就绪队列中只有 1 个进程
{
p=head->next;
time+=p->Serve_Time; //更新当前时间为:当前时间+服务时间
p->Finish_Time=time; //当前时间即为进程完成时间
cout<<p->name<<"\t "<<p->Arrive_Time<<"\t "<<p->Serve_Time<<"\t "
<<p->priority<<"\t "<<p->Finish_Time<<"\t "<<time-p->Arrive_Time<<endl; //输出进程信息
turn_time+=time-p->Arrive_Time; //把周转时间加起来
q=head;
PCB_Delet(head,q); //把执行完的进程从链表删除
}
else //就绪队列中不止一个进程,需要比较
{
q=Serve_Time_min(head,num); //找到服务时间最短的那个进程的前驱结点
p=q->next;
time+=p->Serve_Time;
p->Finish_Time=time; //当前时间即为进程完成时间
cout<<p->name<<"\t "<<p->Arrive_Time<<"\t "<<p->Serve_Time<<"\t "
<<p->priority<<"\t "<<p->Finish_Time<<"\t "<<time-p->Arrive_Time<<endl; //输出进程信息
turn_time+=time-p->Arrive_Time; //把周转时间加起来
PCB_Delet(head,q); //把执行完的进程从链表删除
}
}
turn_time=turn_time/i; //计算平均周转时间
cout<<"平均周转时间为:"<<turn_time<<endl; //输出周转时间
}
void menu() //菜单函数
{
PCB head;
PCB head_1;
PCB head_2;
int a;
cout<<"*********************进程调度算法************************"<<endl;
cout<<"* *"<<endl;
cout<<"* 1. 创建进程 2 查看进程信息 *"<<endl;
cout<<"* *"<<endl;
cout<<"* 可选择的算法: *"<<endl;
cout<<"* *"<<endl;
cout<<"* *"<<endl;
cout<<"* 3.先来先服务法 4.短作业优先法 5.优先级法 *"<<endl;
cout<<"*********************************************************"<<endl;
while(1)
{
cout<<endl<<"请选择要执行的功能:";
cin>>a;
cin.clear();
cin.sync();
if(a==1)
{
ProcessCreate(head); //创建进程
PCB_Sort(head);
Create(head_1);
Create(head_2);
CopyProcess(head,head_1);
PCB_Sort(head_1);
CopyProcess(head,head_2);
PCB_Sort(head_2);
}
else if(a==2)
PCB_View(head); //查看进程信息
else if(a==3)
Process_FCFS(head); //先来先服务法
else if(a==4)
Process_SJF(head_1); //短作业优先发
else if(a==5)
Process_Priority(head_2); //优先级法
else
{
system("cls"); //输入错误清屏重新显示菜单
menu();
}
}
}
int main()
{
menu(); //调用菜单
return 0;
}