一、实验目的:
目的:了解并掌握动态高优先权优先调度算法的理论,掌握动态优先权的设置方式。
任务:模拟实现动态高优先权优先的调度(若数值越大优先权越高,每运行一个时间单位优先权-n,若数值越小优先权越高,每运行一个时间单位优先权+n)。
二、实验内容:
1、实验内容
设置进程体:进程名,进程的到达时间,服务时间,初始优先权,进程状态(W——等待,R——运行,F——完成),进程间的链接指针;
进程初始化:由用户输入进程名、服务时间、初始优先权进行初始化,同时,初始化进程的状态为W;
显示函数:在进程调度前、调度中和调度后进行显示;
排序函数:对就绪状态的进程按照优先权排序。优先权相同时进入等待队列时间早的进程在前,注意考虑到达时间;
调度函数:每次从等待队列队首调度优先权最高的进程执行,状态变化。并在执行一个时间单位后优先权变化,服务时间变化,状态变化。当服务时间为0时,状态变为F;
删除函数:撤销状态为F的进程。
2、实验要求
(1)测试数据可以随机输入或从文件中读入;
(2)必须要考虑到进程的到达时间;
(3)最终能够计算每一个进程的周转时间、带权周转时间
三、实验代码
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<queue>
using namespace std;
struct Pcb
{
int id; //进程编号
string name; //进程名称
int arrive_time; //到达时间
int readTime; //进入就绪队列的时间
int run_time; //运行时间
int serve_time; //服务时间
int state; //0==等待,1==运行,2==完成
int priority; //优先权
int finish_time; //完成时间
} pcb[100001];
int n; //所有进程数量
int x=1; //每过一个时间单位权重的变化
bool operator<(const Pcb& a, const Pcb& b)
{
if (a.priority == b.priority)
return a.readTime > b.readTime;
return a.priority < b.priority;
}
bool cmp(Pcb a, Pcb b)
{
return a.arrive_time < b.arrive_time;
}
priority_queue<Pcb> readyQueue; //就绪队列
void updateState(int id, int time, int sta, int run, int we, int read) //更新进程状态
{
for (int i = 0; i < n; i++)
{
if (pcb[i].id == id)
{
pcb[i].priority = we;
pcb[i].run_time = run;
pcb[i].finish_time = time;
pcb[i].state = sta;
pcb[i].readTime = read;
break;
}
}
}
int init()
{
cout << "请输入要调度的进程:" << endl;
cout << "要调度的进程的数量:";
cin >> n;
for (int i = 0; i < n; i++)
{
cout << "进程名: ";
cin >> pcb[i].name;
cout << "进程到达时间: ";
cin >> pcb[i].arrive_time;
cout << "进程服务时间: ";
cin >> pcb[i].serve_time;
cout << "进程优先权: ";
cin >> pcb[i].priority;
pcb[i].id = i+1;
pcb[i].state = 0;
pcb[i].run_time = 0;
pcb[i].readTime = pcb[i].arrive_time;
}
return n;
}
void show(Pcb pcb[], int n)
{
cout << "-----------------------------------------------------------------------------------------------------------"
<< endl;
cout << " 进程名 " << " 到达时间 "
<< " 服务时间 " << " 开始时间 "
<< " 完成时间 " << " 优先权 " << " 当前状态 " << endl;
for (int i = 0; i < n; i++)
{
cout << setw(8) << pcb[i].name
<< setw(16) << pcb[i].arrive_time
<< setw(15) << pcb[i].serve_time
<< setw(15) << pcb[i].readTime
<< setw(18) << pcb[i].finish_time
<< setw(14) << pcb[i].priority
<< setw(20) << pcb[i].state << endl;
}
cout << endl;
}
int main()
{
n=init();
sort(pcb, pcb + n, cmp); //按到达时间排序
cout << " 进程状态" << endl;
show(pcb, n);
Pcb temp; //临时队首的进程
int nowPcb = 0; //就绪队列的进程数量
for (int i = 0;; i++) //时间刻度
{
printf("\n第%d时刻:\n", i);
for (int j = nowPcb; j < n; j++) //如果开始时刻等于当前时刻,进程入就绪队列
if (pcb[j].arrive_time == i && pcb[i].state == 0)
readyQueue.push(pcb[j]), nowPcb++, temp.readTime = i;
else
break;
if (!readyQueue.empty())
{
temp = readyQueue.top(); //取出当前就绪队列队首并移除
readyQueue.pop();
temp.run_time++; //运行时间+1;
temp.state = 1; //状态设为正在运行
cout << "进程" << temp.name << "正在运行..." << endl;
if (temp.run_time == temp.serve_time)
{
temp.finish_time = i + 1;
temp.state = 2; //状态设为2
temp.readTime = i + 1;
updateState(temp.id, temp.finish_time, temp.state, temp.run_time, temp.priority, temp.readTime);
continue; //下一时刻
}
else
{
temp.priority -= x; //优先权
temp.readTime = i + 1; //重新进入队列的时间
readyQueue.push(temp); //重新进入准备队列
updateState(temp.id, temp.finish_time, temp.state, temp.run_time, temp.priority, temp.readTime); //修改进程状态
}
}
show(pcb, nowPcb);
if (readyQueue.empty() && nowPcb == n) //如果队列为空并且所有进程都已入队,说明完成
break; //跳出循环
}
double turnaround_time = 0;//周转时间
double w_turnaround_time = 0;//带权周转时间
for (int i = 0; i < n; i++)
{
turnaround_time = pcb[i].finish_time - pcb[i].arrive_time;
cout << pcb[i].name << ":";
cout << "周转时间:" << turnaround_time;
w_turnaround_time = turnaround_time / pcb[i].serve_time;
cout << " 带权周转时间:" << w_turnaround_time << endl;
}
return 0;
}
四、实验结果
输入数据:
进程首先按照到达时间排序:
运行过程:
各进程周转时间和带权周转时间:
五、实验总结
通过本次动态高优先权优先进程调度实验,我深入理解了系统在进行进程调度的具体过程,对HPF调度算法有了更加深入的认识,首先要认识到该优先级调度算法是采用的动态优先权,要配合抢占调度方式使用,在创建进程时所赋予的优先权,可以随着进程的推进而发生改变,在本实验中采用的是正在执行的进程,其优先权将随着执行时间的增加而逐渐降低。
代码的主体思路主要是(1)初始化进程块。(2)对进程进行优先级排序。(3)判断队列是否为空;不为空,则开始调用优先级最高的进程。(4)进程运行时间到,则置为就绪状态。(5)输出进程调度结果。在实现的过程中,需要注意的是cpu运行一个时间片后进程的运行时间若还未达到服务时间,此时在进程的优先数减n后,需把它插入就绪队列等待下一次调度。
在具体的实现过程中,关键的是该排序算法: