RR算法总体思路流程图
主要数据结构及参数
typedef struct PCB
{
char name;//进程名
int arrive_time;//到达时间
float cpu_burst;//服务时间
float surplus;//剩余服务时间
int start_time;//开始执行时间
int finish_time;//完成时间
int wait_time;//等待时间
float turn_time;//周转时间
float weighted_ttime;//带权周转时间
bool over;//标记进程是否执行完毕
float response;//响应比
}PCB;//定义进程数据结构
int pcb_num;//进程个数
int time_p;//时间片大小
主要函数
//将进程按照到达先后顺序排序
void sort_arrival(PCB pcb[],int pcb_num){}
//计算周转时间和带权周转时间
void calculator_rr(PCB pcb[],int pcb_num){}
//RR调度算法
void rr(PCB pcb[],int pcb_num,float time_p){}
//计算平均周转时间、平均带权周转时间、平均等待时间
void cal_avg(PCB pcb[],int pcb_num){}
//输出各进程
void show(PCB pcb[],int pcb_num){}
//主函数测试RR调度算法
int main(){}
①sort_arrival()函数:输入进程顺序表pcb[]和进程个数pcb_num作为函数参数,然后将顺序表pcb[]按照到达的先后顺序排序。
②calculator_rr()函数:输入进程顺序表pcb[]和进程个数pcb_num作为函数参数,用于在rr()函数中反复调用,根据顺序表pcb[]中已知的到达时间、完成时间、服务时间,计算周转时间和带权周转时间
③rr()函数:输入进程顺序表pcb[]和进程个数pcb_num作为函数参数,主要是实现RR调度算法,将经RR调度算法计算后的开始执行时间、完成时间、等待时间、周转时间、带权周转时间存入进程顺序表中。
④cal_avg()函数:输入进程顺序表pcb[]和进程个数pcb_num作为函数参数,通过进程顺序表中的等待时间、周转时间、带权周转时间计算出平均等待时间、平均周转时间、平均带权周转时间,然后输出。
⑤show()函数:输入进程顺序表pcb[]和进程个数pcb_num作为函数参数,以表格的形式输出进程顺序表中的各参数信息。
⑥main()函数:主函数中输入进程顺序表,测试FCFS调度函数和SJF调度函数,输出测试结果。
代码
#include<iostream>
#include<iomanip>
#include<queue>
#include<algorithm>
using namespace std;
typedef struct PCB
{
char name;//进程名
int arrive_time;//到达时间
float cpu_burst;//服务时间
float surplus;//剩余服务时间
int start_time;//开始执行时间
int finish_time;//完成时间
int wait_time;//等待时间
float turn_time;//周转时间
float weighted_ttime;//带权周转时间
bool over;//标记进程是否执行
}PCB;//定义进程数据结构
//将进程按照到达先后顺序排序
void sort_arrival(PCB pcb[],int pcb_num)
{
PCB temp;
for(int i=0;i<pcb_num-1;i++)
{
for(int j=i+1;j<pcb_num;j++)
{
if(pcb[i].arrive_time>pcb[j].arrive_time)
{
temp = pcb[i];
pcb[i] = pcb[j];
pcb[j] = temp;
}
}
}
}
//计算周转时间和带权周转时间
void calculator_rr(PCB pcb[],int pcb_num)
{
for(int i=0;i<pcb_num;i++)
{
pcb[i].turn_time = pcb[i].finish_time-pcb[i].arrive_time;//周转时间 = 完成时间-到达时间
pcb[i].weighted_ttime = pcb[i].turn_time/pcb[i].cpu_burst;//带权周转时间 = 周转时间/服务时间
}
}
//RR调度算法
void rr(PCB pcb[],int pcb_num,float time_p)
{
for(int i=0;i<pcb_num;i++)
{
pcb[i].surplus = pcb[i].cpu_burst;
pcb[i].finish_time = 0;
pcb[i].start_time = 0;
pcb[i].turn_time = 0;
pcb[i].wait_time = 0;
pcb[i].weighted_ttime = 0;
}//初始化进程信息
queue<int> wait_q;//定义进程等待队列
sort_arrival(pcb,pcb_num);//将所有进程按照到达的先后顺序排列
int t = pcb[0].arrive_time;//时间从第一个进程到达开始
wait_q.push(0);//将第一个进程加入等待队列
while(wait_q.empty() == false)
{
int t0 =t;//记录需要进行进程切换的时刻
int run;
run = wait_q.front();
wait_q.pop();
if(pcb[run].over == false)//进程第一次执行时
{
pcb[run].start_time = t;//记录第一次开始执行的时间
pcb[run].wait_time = pcb[run].wait_time+t-pcb[run].arrive_time;//累加计算等待时间
pcb[run].over = true;
}
else//进程非第一次执行时
{
pcb[run].wait_time = pcb[run].wait_time+t-pcb[run].finish_time;//累加计算等待时间
}
t = t+min(pcb[run].surplus,time_p);//将时间切换到下个时间片,或进程执行完毕
pcb[run].finish_time = t;//更新每次进程执行结束的时间
pcb[run].surplus = pcb[run].surplus-min(pcb[run].surplus,time_p);//更新进程剩余服务时间
if(t0<pcb[pcb_num-1].arrive_time)
{
for(int i=0;i<pcb_num;i++)
{
if(pcb[i].arrive_time>t0 && pcb[i].arrive_time<=t)
{
wait_q.push(i);
}
}//将所有在t0-t时间内到达的进程按照到达的先后顺序加入等待队列
}
if(pcb[run].surplus != 0)
{
wait_q.push(run);//若进程执行完毕则不再加入等待队列
}
}
calculator_rr(pcb,pcb_num);//计算进程周转时间、带权周转时间
}
//计算平均周转时间、平均带权周转时间、平均等待时间
void cal_avg(PCB pcb[],int pcb_num)
{
float sum1 = 0,sum2 = 0, sum3 = 0;
float avg_turn, avg_weight, avg_wait;
for(int i=0;i<pcb_num;i++)
{
sum1 = sum1+pcb[i].turn_time;
sum2 = sum2+pcb[i].weighted_ttime;
sum3 = sum3+pcb[i].wait_time;
}
avg_turn = sum1/pcb_num;
avg_weight = sum2/pcb_num;
avg_wait = sum3/pcb_num;
cout<<"平均周转时间为:"<<avg_turn<<endl;
cout<<"平均带权周转时间为:"<<avg_weight<<endl;
cout<<"平均等待时间为:"<<avg_wait<<endl;
}
//输出各进程
void show(PCB pcb[],int pcb_num)
{
cout<<"-----------------------------------------------------------------------------"<<endl;
cout<<"进程名|到达时间|服务时间|开始执行时间|完成时间|周转时间|带权周转时间|等待时间"<<endl;
cout<<"-----------------------------------------------------------------------------"<<endl;
for(int i=0;i<pcb_num;i++)
{
cout<<pcb[i].name;
cout<<"\t"<<pcb[i].arrive_time;
cout<<"\t"<<pcb[i].cpu_burst;
cout<<"\t"<<"\t"<<pcb[i].start_time;
cout<<"\t"<<pcb[i].finish_time;
cout<<"\t"<<pcb[i].turn_time;
cout<<"\t"<<setprecision(3)<<pcb[i].weighted_ttime;
cout<<"\t"<<pcb[i].wait_time<<endl;
}
}
//主函数测试RR调度算法
int main()
{
int pcb_num;//进程个数
cout<<"请输入进程总个数:"<<endl;
cin>>pcb_num;
PCB pcb[pcb_num];
for(int i=0;i<pcb_num;i++)
{
cout<<"请输入进程名:";
cin>>pcb[i].name;//输入各进程名
cout<<"请输入进程到达时间:";
cin>>pcb[i].arrive_time; //输入各进程的到达时间
cout<<"请输入进程需要服务的时间:";
cin>>pcb[i].cpu_burst; //输入各进程需要服务的时间
pcb[i].over = false;//初始时,所有进程执行状态都为false
pcb[i].surplus = pcb[i].cpu_burst;//初始时,所有进程剩余服务时间都为服务时间
pcb[i].finish_time = 0;
pcb[i].start_time = 0;
pcb[i].turn_time = 0;
pcb[i].wait_time = 0;
pcb[i].weighted_ttime = 0;
}
cout<<"--------------------------------"<<endl;
cout<<" RR调度结果 "<<endl;
cout<<"--------------------------------"<<endl;
int time_p;//时间片大小
bool goon = true;
while(goon == true)
{
cout<<"请输入时间片大小:";
cin>>time_p;
rr(pcb,pcb_num,time_p);
show(pcb,pcb_num);
cout<<endl;
cal_avg(pcb,pcb_num);
cout<<"是否继续测试RR调度结果(是则输入1,否则输入0):";
cin>>goon;
}
return 0;
}
结果
结果分析
时间片轮转RR调度算法很大程度上取决于时间片大小的选取,时间片的大小直接决定了时间片轮转RR调度算法的效率,时间片选取过小,会频繁发生终端,需要不断进行上下文的切换,严重增加了系统的开销;时间片选取过大则时间片轮转RR调度算法直接退化为先来先服务FCFS调度算法。从表格可以看出,时间片轮转RR调度算法的各参数值都较高,效率较其他算法不算高,而且明显时间片轮转RR调度算法对时间片的选取要求较高,需要实现知道各进程的参数情况才能够选取合适的时间片大小。