多级队列调度和多级反馈队列调度算法的实现
多级队列调度算法
- 多级队列:该算法将系统中的进程就绪队列从一个拆分为若干个,将不同类型或性质的进程固定分配在不同的就绪队列,不同的就绪队列采用不同的调度算法,一个就绪队列中的进程可以设置不同的优先级,不同的就绪队列本身也可以设置不同的优先级。
多级队列调度算法由于设置多个就绪队列,因此对每个就绪队列就可以实施不同的调度算法,因此,系统针对不同用户进程的需求,很容易提供多种调度策略。
题目描述:
- 设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 |
程序功能
- 对于给定的数据使用多级队列调度算法进行分析计算周转时间。其中多级队列分为RQ1和RQ2 ,RQ1采用的是时间片长度为7的时间片轮转算法,RQ2采用的是短进程优先算法。并且RQ1的优先级高于RQ2(即只有在RQ1内所有程序运行结束,RQ2才能开始运行)
设计思路
- 时间片轮转:首先对RQ1按照等待时间长短排序,然后从头设置循环,只要队列不空就一直进行下去,每次取队头RQ1的下一个元素(RQ1仅用作标志,不存储数据)判断need是否小于等于时间片大小,小于等于则置为0后踢出队列进入finish队列,大于则将need减去时间片大小,然后将其移动至队尾。
- 短进程优先:开始前需要对RQ2按照剩余执行时间大小进行排序,与时间片轮转法类似,不同的是这里一旦开始执行就直接执行完毕,然后下一个进程上处理机运行。
![](https://img-blog.csdnimg.cn/20210411194558752.png)
数据结构
- 本程序每个进程用一个PCB表示,每个PCB内含有name(标识符)、need(当前仍然需要多长时间才能运行结束)、turn(周转时间(等于等待时间+运行时间))、next指针(指向等待队列的下一个进程)。两个队列的头节点分别为RQ1、RQ2还有一个结束队列Finish(运行结束后进程从原队列进入这里)
typedef struct tag_pcb {
char name[8];
int need = 0;//需要运行的时间
int turn = 0;//周转时间=等待时间+运行时间
struct tag_pcb* next = NULL;
}PCB;
PCB* RQ1=new PCB, * RQ2 = new PCB, * Finish = new PCB;
代码实现:
![](https://img-blog.csdnimg.cn/992a49478a0a42869b872971a13fc151.gif)
#include<iostream>
#include <fstream>
using namespace std;
typedef struct tag_pcb {
char name[8];
int need = 0;//需要运行的时间
int turn = 0;//周转时间=等待时间+运行时间
struct tag_pcb* next = NULL;
}PCB;
PCB* RQ1=new PCB, * RQ2 = new PCB, * Finish = new PCB;
const int TimePiece = 7;//时间片长度
void ReadFile(){
ifstream In("RQ1.txt");
PCB* Current = RQ1;
while (!In.eof()) {
PCB* Cur = new PCB;
In >> Cur->name >> Cur->need>> Cur->turn;
Current->next = Cur;
Current = Current->next;
}
In.close();
ifstream In1("RQ2.txt");
PCB* Current1 = RQ2;
while (!In1.eof()) {
PCB* Cur1 = new PCB;
In1 >> Cur1->name >> Cur1->need >> Cur1->turn;
Current1->next = Cur1;
Current1 = Current1->next;
}
In1.close();
}
void Q1_Insert(PCB a) { //时间片轮转算法队列的插入(插入尾部)
PCB* Current = RQ1;
while (Current->next != NULL)
Current = Current->next;
Current->next = new PCB;
*Current->next = a;
//Current->next = &a;
Current->next->next = NULL;
}
void Q2_Insert(PCB b) { //短进程优先调度算法队列的插入
PCB* Current = RQ2;
while (Current->next != NULL)
Current = Current->next;
Current->next = new PCB;
*Current->next = b;
Current->next->next = NULL;
}
void Fin_Insert(PCB c) { //短进程优先调度算法队列的插入
PCB* cc = new PCB;
*cc = c;
cc->next = Finish->next;
Finish->next = cc;
}
void Q2_sort(PCB *T) {
PCB* X = new PCB;//用来保存排序后的链表
PCB* p = new PCB;//用来保存当此最小值的前一位
PCB* Current = T->next;
PCB * PreCurrent = T;
PCB* TailX = X;
while (T->next != NULL) {
int tem = 999999;
Current = T->next;
PreCurrent = T;
while (Current != NULL) {
if (Current->need < tem) {
tem = Current->need;
p = PreCurrent;
//cout << "处理" << p->name << p->need << "\n";
}
Current = Current->next;
PreCurrent = PreCurrent->next;
}
TailX->next = p->next;
TailX = TailX->next;
if (p->next->next != NULL)
p->next = p->next->next;
else
p->next = NULL;
}
*T = *X;
}
int main()
{
ReadFile();
int clock = 0; //时钟
while (RQ1->next != NULL) {//表示RQ1还有元素
int t = TimePiece;
PCB* Current = RQ1->next;
int fin = 0;
if (Current->need <= t)
t = Current->need, fin = 1;
clock += t;//表示pi运行t
//输出计算过程
//cout << "\n" << Current->name << "_____" << Current->turn << "__+ ___" << clock << "__= ___" << Current->turn +clock << "\n";
Current->need -= t;
if (fin)
Current->turn += clock, Fin_Insert(*Current);//运行结束
else
Q1_Insert(*Current);//进入队尾等待运行
if (Current->next == NULL)
break;
RQ1->next = Current->next;
}
clock = 0;//时钟要清空一次
Q2_sort(RQ2);//先排序
cout << "RQ2:__";
for (PCB* Current2 = RQ2->next; Current2 != NULL; Current2 = Current2->next)
cout << Current2->name << "--";
while (RQ2->next != NULL) {//表示RQ2还有元素(到这一步默认RQ1已经为空)
PCB* Current3 = RQ2->next;
int t = Current3->need;
clock += t;//表示pi运行t
Current3->need -= t;//实质为清空
Current3->turn += clock;
Fin_Insert(*Current3);
if (Current3->next == NULL)
break;
RQ2->next = Current3->next;
}
int SUM = 0;
for (PCB* Current2 = Finish->next; Current2 != NULL; Current2 = Current2->next) {
cout << "\n" << Current2->name <<"\t"<< Current2->turn ;
SUM += Current2->turn;
}
cout << "\n总周转时间为:" << SUM << "\n";
}
- 多级队列调度测试结果:
附:
多级反馈队列调度算法如下原理:
- 1、设有N个队列(Q1,Q2…QN),其中各个队列对于处理机的优先级是不一样的,也就是说位于各个队列中的作业(进程)的优先级也是不一样的。一般来说,优先级Priority(Q1) > Priority(Q2) > … > Priority(QN)。怎么讲,位于Q1中的任何一个作业(进程)都要比Q2中的任何一个作业(进程)相对于CPU的优先级要高(也就是说,Q1中的作业一定要比Q2中的作业先被处理机调度),依次类推其它的队列。
- 2、对于优先级最低的队列来说,里面是遵循时间片轮转法。也就是说,位于队列QN中有M个作业,它们的运行时间是通过QN这个队列所设定的时间片来确定的;对于其他队列,遵循的是先来先服务算法,每一进程分配一定的时间片,若时间片运行完时进程未结束,则进入下一优先级队列的末尾。
- 3、各个队列的时间片是一样的吗?
不一样,这就是该算法设计的精妙之处。各个队列的时间片是随着优先级的增加而减少的,也就是说,优先级越高的队列中它的时间片就越短。同时,为了便于那些超大作业的完成,最后一个队列QN(优先级最低的队列)的时间片一般很大(不需要考虑这个问题)。
上述程序在某一进程在一级队列运行一轮后没有运行完毕,若加入二级队列而不是加入原队列的尾部,则可以实现简单的多级反馈队列调度算法
两种算法的不同之处就在于:当一个RQ1中的进程在时间片结束之后是回到当前的队尾还是到RQ2队列之中。
在上述程序中也很容易实现:
if (fin)
Current->turn += clock, Fin_Insert(*Current);//运行结束
else
Q1_Insert(*Current);//进入队尾等待运行
修改为:
if (fin)
Fin_Insert(*Current);//运行结束
else
Q2_Insert(*Current);//进入二级队列等待运行
Current->turn += clock,
上述两种代码分别实现了上述两种功能,执行时只需选一种在相应位置即可。
- 多级反馈队列调度测试结果:
由分析上述数据容易发现:在该测试数据的情况下多级反馈队列调度算法是要优于多级队列调度的