1. 问题描述
1.1 多级队列调度算法
(1) 循环轮转调度算法
当CPU空闲时,选取就绪队列首元素,赋予一个时间片,当时间片用完时,该进程转为就绪态并进入就绪队列末端。
(2) 短作业优先调度算法
按作业请求运行的时间长短进行调度。
1.2 伪代码
typedef struct tag_pcb {
char name[8];
int need;//须运行的时间
int turn;//周转时间
struct tag_pcb *next;
} PCB;
PCB * RQ1,*RQ2,*Finish;
int clock=0; //时钟
main ( ) {
输入RQ1;
输入RQ2;(最好从文件读入)
while(RQ1 != NULL){
从RQ1中选取一进程Pi准备运行;
计算其运行的时间t;
clock+=t; //表示Pi运行t;
if (Pi完成) 计算其turn;
否则 Pi加入到队尾;
}
while(RQ2!=NULL){
从RQ2中选取一进程Pi准备运行;
clock+=Pi.need;
计算Pi的turn;
}
输出进程的周转时间;
}
1.3 测试数据
设RQ分为RQ1和RQ2,RQ1采用轮转法,时间片q=7.
RQ1>RQ2,RQ2采用短进程优先调度算法。
测试数据如下:RQ1: P1-P5, RQ2: P6-P10
进程 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10
运行时间 16 11 14 13 15 21 18 10 7 14
已等待时间 6 5 4 3 2 1 2 3 4 5
2.实现思路
2.1 文件读取
2.2 进程控制块
为进程控制块PCB类添加静态成员_sum,代表从开始到某程序运行一共耗费的时间。_turn代表周转时间,最终会被程序输出。_need代表还需要的时间。_isDone代表该进程是否运行完成。
2.3 调度算法
(1) 轮转法
设置还剩下需要运行的进程数all,循环运行所有_isDone == false的进程,即未运行完成的进程,,直至all等于0。若该进程还需要运行的时间_need大于时间片clockPiece,则_need -= clockPiece,代表时间片被该进程消耗,并将该进程的_turn加上时间片。否则若_need < colckPiece,即该进程能够在时间片内运行完成,则设置该进程_isDone = true。在进程运行过程中,_sum代表某进程运行完成时总共的运行时间,也就是下一个进程运行时需要等待的时间。
(2) 短进程优先
将所有进程按所需时间放入最小堆,每次取堆顶元素,将该线程运行,_sum代表某进程运行完成时总共的运行时间,也就是累加前面所有进程的_need,则下一个进程的_turn为已等待时间加上_sum。
3. 核心代码
3.1 轮转法
void dealRQ1(std::vector<PCB>& PCBlist, int clockPiece = 7) {
int cnt = 0, all = process1;
while (all) {
if (PCBlist[cnt % process1]._isDone == true) {
cnt++;
continue;
}
if (PCBlist[cnt]._need > clockPiece) {
PCBlist[cnt]._need -= clockPiece;
PCB::_sum += clockPiece;
}
else {
PCB::_sum += PCBlist[cnt]._need;
PCBlist[cnt]._need = 0;
PCBlist[cnt]._turn += PCB::_sum;
PCBlist[cnt]._isDone = true;
all--;
}
cnt = ++cnt % process1;
}
}
3.2 短进程优先
std::vector<PCB> dealRQ2(std::priority_queue<PCB> PCBqueue) {
std::vector<PCB> vecPCB;
while (!PCBqueue.empty()) {
auto pcb = PCBqueue.top();
PCB::_sum += pcb._need;
pcb._turn += PCB::_sum;
vecPCB.push_back(pcb);
PCBqueue.pop();
}
return vecPCB;
}