1.问题描述及需求分析
设计程序模拟进程的高响应比HRRN和时间片轮转RR调度过程。假设有n个进程分别在T1, … ,Tn时刻到达系统,它们需要的服务时间分别为S1, … ,Sn。如果选择RR算法,还需要指定时间片大小q。分别采用高响应比HRRN和时间片RR进程调度算法进行调度,计算每个进程的完成时间,周转时间、带权周转时间和等待时间,并且统计n个进程的平均周转时间、平均带权周转时间和平均等待时间。最后,对两个算法做出比较评价。
2.实验设计
HRRN(hignest response ratio next),该算法既考虑了作业的等待时间过长,又考虑了作业的运行时间,既照顾了短作业,又不致使长作业等待时间过长,从而改善了处理机调度的性能。我们引入一个动态优先级,即优先级是可以改变的,令他随等待时间延长而增加,这将使长作业的优先级在等待期间不断的增加,等到足够的时间后,必然有机会获得处理机。该优先级的变化规律可以描述为:
优先权 =(等待时间+要求服务时间)/要求服务时间
=1+等待时间/要求服务时间
1、如果作业的等待时间相同,则要求服务的时间越短,其优先级越高,类似于SJF算法。
2、当要求服务的时间相同时,作业的优先权又可以决定于其等待时间,类似于FCFS算法。
3、对于长作业的优先级,可以随等待时间的增加而提高,当其等待时间足够长时,也可以获得处理机。
在RR中,系统根据FCFS策略,将所有的就绪进程排成一个就绪队列,并可设置每个一定时间间隔(20ms)即产生一次中断,激活系统中的进程调度程序,完成一次调度,将CPU分配给队首进程,令其执行。当该进程的时间片耗尽或者运行完毕后,系统再次将CPU分配给新的队首进程(或新到达的紧迫进程)。由此,可保证就绪队列中的所有进程在一个确定的时间段内,都能够获得一次CPU执行。
在RR调度算法中,应在何时进行进程的切换,可分为两种情况:①若一个时间片尚未用完,正在运行的进程便已经完成,就立即激活调度程序,将他从就绪队列删除,再调度就绪队列中队首的其他进程运行,并启动一个新的时间片。②在一个时间片用完时,计时器阻断处理程序被激活。如果进程尚未运行完毕,调度程序把他送往就绪队列的末尾。
3.实验代码
#include
#include
#include
#include
#include
#include
using namespace std;
class PCBNode
{
friend void sort(vector&);
friend void RR(vector&, const float&);
public:
char name; //进程名
float arrivaltime; //到达时间
float servicetime; //运行时间
float remainingtime;//剩余服务时间
float waittime; //等待时间
float finishtime; //完成时间
float roundtime; //周转时间
float weighttime; //带权周转时间
float prior; //优先级
float rrtime; //时间片轮转法的完成标记
int flag; //只是标记默认排序的方式
deque readyQueue; //双端队列
void display() const; //显示进程信息
bool crt(float rr); //计算剩余时间
void cft(float time); //计算结束时间
float ct1(); //计算周转时间
float ct2(); //计算带权周转时间
operator float() const
{
if (1= =flag)
{
return arrivaltime;
}
else if (2= =flag)
{
return servicetime;
}
else if(3= =flag)
{
return prior;
}
else if (4= =flag)
{
return waittime;
}
}
//构造函数,初始化进程
PCBNode() = default;
PCBNode(char nameP, float arrivaltimeP, float servicetimeP)
:name(nameP), arrivaltime(arrivaltimeP), servicetime(servicetimeP), rrtime(servicetimeP), remainingtime(servicetimeP)
{
waittime = 0;
}
};
//按到达时间排序
void sort(vector& pcbs) {
int index;
int n = pcbs.size();
for (int i = 0; i < n; i++) {
index = i;
for (int j = i + 1; j < n; j++) {
if (pcbs[j].arrivaltime < pcbs[i].arrivaltime)
index = j;
}
if (index != i){
PCBNode temp;
temp = pcbs[i];
pcbs[i] = pcbs[index];
pcbs[index] = temp;
}
}
}
void PCBNode::display() const {
cout << setw(2) << name
<<setw(8)<< arrivaltime
<<setw(10)<< servicetime << endl;
}
//计算剩余时间,时间不足一个时间片返回false,否则返回true
bool PCBNode::crt(float rr) {
if (remainingtime <= rr)
return false;
else {
remainingtime -= rr;
return true;
}
}
//计算结束时间
void PCBNode::cft(float time) {
finishtime = time;
}
//计算周转时间
float PCBNode::ct1() {
return finishtime - arrivaltime;
}
//计算带权周转时间
float PCBNode::ct2() {
return (finishtime - arrivaltime) / servicetime;
}
class Manage
{
public:
vector ProcessList; //初始进程列表
vector RRProcess; //作为中间桥梁
vector RunProcess; //用来存放运行的进程
vector FinallProcess; //存放最终结果
float allroundtime;
float allweightroundtime;
float averroundtime;
float averweighttime;
void add(PCBNode &val)
{
ProcessList.push_back(val);
}
//取得平均带权时间和平均带权周转时间
void AverageTime(vector ProcessList)
{
allroundtime = 0, allweightroundtime = 0;
for (size_t i = 0; i < ProcessList.size(); i++)
{
allroundtime = allroundtime + ProcessList[i].roundtime;
allweightroundtime = allweightroundtime + ProcessList[i].weighttime;
}
averroundtime = allroundtime / ProcessList.size();
averweighttime = allweightroundtime / ProcessList.size();
cout << “平均带权时间:” << averroundtime << endl;
cout << “平均带权周转时间:” << averweighttime << endl;
}
void Prior_HRRN(int i, const int tag)
{
for (; i < ProcessList.size(); i++)
{
if (ProcessList[i].arrivaltime < ProcessList[tag].finishtime)
{
ProcessList[i].waittime = ProcessList[tag].finishtime - ProcessList[i].arrivaltime;
}
else
{
ProcessList[i].waittime = 0;
}
ProcessList[i].finishtime = ProcessList[i].servicetime + ProcessList[i].waittime + ProcessList[i].arrivaltime;
ProcessList[i].roundtime = ProcessList[i].finishtime - ProcessList[i].arrivaltime;
ProcessList[i].weighttime = ProcessList[i].roundtime / ProcessList[i].servicetime;
ProcessList[i].prior = ProcessList[i].waittime / ProcessList[i].servicetime + 1;
}
}
void Base_HRRN(int i, const int tag)
{
for (int k = 0; k < ProcessList.size(); k++)
{
ProcessList[k].flag = 3;
}
for (; i < ProcessList.size(); i++)
{
//计算优先级
Prior_HRRN(i, tag);
//按优先级高低排序
sort(ProcessList.begin() + 1, ProcessList.end(), greater());
//优先级高的进程首先执行
ProcessList[i].finishtime = ProcessList[i].servicetime + ProcessList[i].waittime + ProcessList[i].arrivaltime;
ProcessList[i].roundtime = ProcessList[i].finishtime - ProcessList[i].arrivaltime;
ProcessList[i].weighttime = ProcessList[i].roundtime / ProcessList[i].servicetime;
for (int j = i + 1; j < ProcessList.size(); j++)
{
ProcessList[j].finishtime = ProcessList[j].roundtime = 0;
ProcessList[i].waittime = ProcessList[i-1].waittime = 0;
}
break;
}
}
void HRRN()
{
//对于第一个进程来说优先运行
ProcessList[0].waittime = 0.0;
ProcessList[0].finishtime = ProcessList[0].servicetime + ProcessList[0].waittime + ProcessList[0].arrivaltime;
ProcessList[0].roundtime = ProcessList[0].finishtime - ProcessList[0].arrivaltime;
ProcessList[0].weighttime = ProcessList[0].roundtime / ProcessList[0].servicetime;
int length = ProcessList.size();
int tag = 0;
//当有一个进程运行完时,都要计算其余的每个进程的优先级
for (int i = 1; i < length; i++)
{
Base_HRRN(i, i - 1);
}
Print(ProcessList);
AverageTime(ProcessList);
FinallProcess.clear();
ProcessList.clear();
RunProcess.clear();
}
void RR(vector& pcbs, const float& rr) {
unsigned i = 1;
int n = pcbs.size();
//按到达时间排序
sort(pcbs);
deque queue; //双端队列
//第一个到达的进程进入队列
queue.push_back(pcbs[0]);
float time = pcbs[0].arrivaltime;
while (n!=0) {
//计算当前时间
if (!queue.empty()) {
if (queue[0].remainingtime < rr)
time += queue[0].remainingtime;
else
time += rr;
}
else {
time = pcbs[i].arrivaltime;
queue.push_back(pcbs[i]);
i++;
if (queue[0].remainingtime < rr)
time += queue[0].remainingtime;
else
time += rr;
}
//在进程结束之前到达的新进程进入队列
while (i < pcbs.size() && pcbs[i].arrivaltime <= time) {
queue.push_back(pcbs[i]);
pcbs[i].readyQueue = queue;
i++;
}
//未执行完的进程放入队尾,否则从队列中删除
if (queue[0].crt(rr)) {
PCBNode t = queue[0];
queue.pop_front();
queue.push_back(t);
}
else {
for (unsigned j = 0; j < pcbs.size(); j++) {
if (pcbs[j].name == queue[0].name) {
pcbs[j].readyQueue = queue;
pcbs[j].cft(time);
}
}
queue.pop_front();
n–;
}
}
}
void Print(vector ProcessList)
{
for (int i = 0; i < ProcessList.size(); i++)
{
ProcessList[i].flag = 1;
}
sort(ProcessList.begin(), ProcessList.end());
cout << “-进程名” << “–完成时间”<<"–等待时间"<< “–周转时间” << “–带权周转时间” << endl;
for (int i = 0; i < ProcessList.size(); i++)
{
cout << setw(3) <<ProcessList[i].name << setw(8) << ProcessList[i].finishtime
<< setw(12) <<ProcessList[i].waittime<< setw(10) << ProcessList[i].roundtime
<< setw(10) << ProcessList[i].weighttime;
cout<< endl;
}
}
void Menu()
{
cout << “1-高响应比HRRN,2-时间片RR” << endl;
}
};
int main()
{
int num_process;
char name;
float arrivaltime, servicetime;
Manage process;
int choose = 0;
char end = ‘y’;
int piece = 0;
int count = 1;
while (‘y’==end ||‘Y’==end)
{
fflush(stdin);
process.Menu();
cout << “请输入你的选择:”;
cin >> choose;
if (choose < 1 || choose>2)
{
cout << “请重新输入!!!” << endl;
}
else
{
// cout << “请输入进程的个数:”;
// cin >> num_process;
num_process = 5;
vector pcbs(num_process);
pcbs[0] = PCBNode(‘a’, 0, 6);
pcbs[1] = PCBNode(‘b’, 1, 2);
pcbs[2] = PCBNode(‘c’, 2, 5);
pcbs[3] = PCBNode(‘d’, 3, 9);
pcbs[4] = PCBNode(‘e’, 4, 8);
cout << “编号 " << " 到达时间 " << " 服务时间” << endl;
for (int i = 0; i < num_process; i++) {
pcbs[i].display();
}
PCBNode obj(‘a’, 0, 6);
process.add(obj);
PCBNode obj1(‘b’, 1, 2);
process.add(obj1);
PCBNode obj2(‘c’, 2, 5);
process.add(obj2);
PCBNode obj3(‘d’, 3, 9);
process.add(obj3);
PCBNode obj4(‘e’, 4, 8);
process.add(obj4);
// for (int i = 0; i < num_process; ++i)
// {
// cout << “请输入第” << i + 1 << “个进程的名称,提交时间,运行时间:”;
// cin >> name;
// cin >> arrivaltime;
// cin >> servicetime;
// PCBNode obj(name, arrivaltime, servicetime);
// process.add(obj);
// pcbs[i] = PCBNode(name, arrivaltime, servicetime);
// }
switch (choose)
{
case 1:
process.HRRN();
break;
case 2:
{
cout << “请输入时间片的大小:”;
cin >> piece;
process.RR(pcbs,piece);
float sum1 = 0.0, sum2 = 0.0;
cout << "编号 " << " 完成时间 " << " 周转时间 " << " 带权周转时间 " << " 就绪队列 "<< endl;
for (int i = 0; i < num_process; i++) {
cout << setw(2)<< pcbs[i].name
<<setw(9)<< pcbs[i].finishtime
<<setw(10)<< pcbs[i].ct1()
<<setw(14)<< pcbs[i].ct2()<<setw(6);
for (int j = 0; j<pcbs[i].readyQueue.size(); j++) {
cout<< pcbs[i].readyQueue[j].name << " ";
}
cout << endl;
sum1 += pcbs[i].ct1();
sum2 += pcbs[i].ct2();
}
cout << “平均周转时间:” << sum1 / float(num_process) << endl;
cout << “平均带权周转时间:” << sum2 / float(num_process) << endl;
cout<<endl;
process.FinallProcess.clear();
process.ProcessList.clear();
process.RunProcess.clear();
break;
}
default:
break;
}
cout << "是否继续选择算法(Y/y):";
fflush(stdin);
cin >> end;
}
}
return 0;
}
4.实验结果与分析
实验过程:
(1)本次实验我使用的是结构体作为每个进程
(2)在函数内使用向量和队列数据类型进行对进程操作
(3)并设置了两个主要算法函数HRRN和RR算法
(4)得到第一个执行的进程的具体位置下标
让用户选择使用HRRN算法还是RR算法进行对数据调度
(5)在两个算法中对全局数据数组中数据进行改变
(6)最后HRRN算法结束后在算法函数内调用输出函数
(7)RR算法在主函数内直接输出数据
5.实验心得
HRRN算法,在每次进行调度时,都需要先做响应比的计算,显然会增加系统开销。
RR算法,时间片的选择大小对系统性能有很大的影响。若选择较小的时间片,将有利于短作业,因为他能在该时间内完成。但时间片小,意味着频繁地执行进程调度和进程上下文的切换,会增加系统的开销。若时间片选择得太长,且为使每个进程都能在一个时间片完成,RR算法便会退化为FCFS算法,无法满足短作业和交互式用户的需求。一个较为可取的时间片是略大于一次典型的交互所需要的时间,使大多数交互式进程能够在一个时间片内完成,从而获得很小的响应时间。