1 多级反馈队列调度算法
1.1 作用
如果有很多任务排队等着被处理,哪个任务先被处理,哪个任务后处理,这个需要由操作系统决定,这就是调度。
多级反馈队列调度算法 是目前操作系统调度算法中被公认的一种较好的调度算法。它可以满足各种类型进程的需要,既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。
1.2 应用范围
此算法应用于同一个资源的多个使用者可分优先级使用资源的情况
1.3 基本概念
多级反馈队列调度算法是一种根据先来先服务原则给就绪队列排序,为就绪队列赋予不同的优先级数,不同的时间片,按照优先级抢占CPU的调度算法。算法的实施过程如下:
-
按照先来先服务原则排序,设置N个就绪队列为Q1,Q2…QN,每个队列中都可以放很多作业;
-
为这N个就绪队列赋予不同的优先级,第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低;
-
设置每个就绪队列的时间片,优先权越高,算法赋予队列的时间片越小。时间片大小的设定按照实际作业(进程)的需要调整;
-
进程在进入待调度的队列等待时,首先进入优先级最高的Q1等待。
-
首先调度优先级高的队列中的进程。若高优先级中队列中已没有调度的进程,则调度次优先级队列中的进程。例如:Q1,Q2,Q3三个队列,只有在Q1中没有进程等待时才去调度Q2,同理,只有Q1,Q2都为空时才会去调度Q3。
-
***对于同一个队列中的各个进程,按照 ( 时间片轮转法调度 )***。比如Q1队列的时间片为N,那么Q1中的作业在经历了时间片为N的时间后,若还没有完成,则进入Q2队列等待,若Q2的时间片用完后作业还不能完成,一直进入下一级队列,直至完成。
-
在低优先级的队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业即抢占式调度CPU。
1.4 使用方法及步骤
假设系统中有3个就绪队列Q1,Q2,Q3,时间片分别为2,4,8。
现在有3个作业J1,J2,J3分别在时间 0 ,1,3时刻到达。
而它们所需要的CPU时间分别是3,2,1个时间片。
-
时刻0: J1到达。于是进入到队列1 , 运行1个时间片 , 时间片还未到,此时J2到达。
-
时刻1: J2到达。 由于时间片仍然由J1掌控,于是等待。 J1在运行了1个时间片后,已经完成了在Q1中的2个时间片的限制,于是J1置于Q2等待被调度。现在处理机分配给J2。
-
时刻2: J1进入Q2等待调度,J2获得CPU开始运行。
-
时刻3:J3到达,由于J2的时间片未到,故J3在Q1等待调度,J1也在Q2等待调度。
-
时刻4:J2处理完成,由于J3,J1都在等待调度,但是J3所在的队列比J1所在的队列的优先级要高,于是J3被调度,J1继续在Q2等待。
-
时刻5:J3经过1个时间片,完成。
-
时刻6:由于Q1已经空闲,于是开始调度Q2中的作业,则J1得到处理器开始运行。
-
时刻7:J1再经过一个时间片,完成了任务。于是整个调度过程结束。
1.5 源码
编写并调试一个模拟的进程调度程序,采用“多级反馈队列轮转法”调度算法对五个进程进行调度。
注意:linux 平台下的 unistd.h 头文件相当于 windows平台的 windows.h 头文件
#include <iostream>
#include <queue>
#include <list>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
using namespace std;
unsigned int q_id = 0; // 队列进程号的全局变量
unsigned int stime = 0; // 进程开始执行的时间
const unsigned int Q_NUM = 3; // 总就绪队列数
const unsigned int TOTAL_PRO_NUM = 5; // 总进程数
const unsigned int INIT_PRO_NUM = 3; // 初始就绪进程数
unsigned int pro_num = 3; // 当前进程个数
// 进程信息
struct Pro
{
unsigned int pid; // 进程ID
unsigned int start_time; // 开始执行时间
unsigned int need_time; // 预计执行时间
unsigned int end_time; // 完成时间
unsigned int run_time; // 已经运行时间
unsigned int count; // 计数器
};
// 多级就绪队列节点信息
struct Node
{
queue<Pro> q; // 就绪队列
unsigned int priority; // 队列优先级
unsigned int cap; // 时间片
};
// 进程调度类
class Scheduling
{
private:
queue<Pro> qp; // 队列
list<Pro> lp; // 链表
list<Node> ln; // 链表队列
unsigned int cap; // 时间片
public:
Scheduling(/* args */);
~Scheduling();
void create_q_pro(); // 创建进程queue的函数
void create_l_pro(); // 创建进程list的函数
void create_node(); // 创建node队列
void fcfs(); // FCFS : 先来先服务调度算法
void rr(); // RR : 轮转调度算法
void mfq(); // MFQ : 多级反馈队列调度算法
};
Scheduling::Scheduling(/* args */)
{
cap = 10; // 初始化时间片
}
Scheduling::~Scheduling()
{
}
void Scheduling::create_q_pro()
{
Pro item;
item.pid = (++q_id);
item.count = 0;
item.need_time = rand() % 100 + 10; // 预计需求时间 在 10 ~ 100 之间
item.run_time = 0;
//
qp.push(item);
printf("创建进程 PID= %d: 执行所需时间= %d\n", item.pid, item.need_time);
}
void Scheduling::create_l_pro()
{
Pro item;
item.pid = ++q_id;
item.count = 0;
item.need_time = rand() % 200 + 10; // 预计需求时间 在 10 ~ 100 之间
item.run_time = 0;
//
lp.push_back(item);
printf("创建进程 PID = %d: 执行所需时间 = %d\n", item.pid, item.need_time);
}
void Scheduling::create_node()
{
for (int j = 0; j < Q_NUM; j++)
{
Node node;
node.priority = 1 + j; // 初始队列最高优先级1
node.cap = 20 * pow(2, j); // 初始化时间片 20
int i;
// 在最高优先队列中创建 3 个进程
for (i = 0; j == 0 && i < INIT_PRO_NUM; i++)
{
Pro item;
item.pid = (++q_id);
item.count = 0;
item.need_time = rand() % 100 + 10; // 预计需求时间 在 10 ~ 100 之间
item.run_time = 0;
//
node.q.push(item);
printf("创建进程 PID= %d: 执行所需时间 = %d\n", item.pid, item.need_time);
printf("\n");
}
//
ln.push_back(node);
}
}
// 先来先服务调度算法
void Scheduling::fcfs()
{
int i, rd;
printf("-------先来先服务调度算法-------\n");
for (i = 0; i < 5; i++)
{
create_q_pro();
printf("\n");
}
while (!qp.empty())
{
Pro *p = &qp.front();
p->start_time = stime;
printf("创建进程 PID= %d: 执行所需时间 = %d\n", p->pid, p->need_time);
sleep(p->end_time);
p->end_time = p->start_time + stime;
printf("结束时间%d\n", p->end_time);
printf("\n");
qp.pop();
stime = p->end_time;
//
// rd = rand() % 10;
// if (rd > 6)
// {
// create_q_pro();
// printf("\n");
// }
}
}
// 轮转调度算法
void Scheduling::rr()
{
int i, rd;
stime = 0;
printf("-------时间片轮转法(时间片 = %d)-------\n", cap);
for (i = 0; i < 5; i++)
{
create_q_pro();
printf("\n");
}
while (!qp.empty())
{
Pro *p = &qp.front();
p->start_time = stime;
printf("进程PID=%d: 执行还需时间%d 开始执行时间%d ", p->pid, p->need_time, p->start_time);
if (p->need_time > cap)
{
sleep(cap);
// sleep(3);
p->need_time = p->need_time - cap;
p->end_time = cap;
p->run_time = p->run_time + cap;
stime = stime + cap;
++(p->count);
printf("第 %d 次执行,已执行时间 = %d\n", p->count, p->run_time);
qp.push(qp.front());
qp.pop();
}
else
{
sleep(p->end_time);
// sleep(3);
stime = stime + p->end_time;
p->end_time = stime;
p->run_time = p->run_time + p->need_time;
++(p->count);
printf("第 %d 次执行,已执行时间 = %d 结束时间 = %d 执行完毕\n", p->count, p->run_time, p->end_time);
p->end_time = 0;
qp.pop();
}
printf("\n");
// rd = rand() % 10;
// if (rd > 6)
// {
// create_q_pro();
// printf("\n");
// }
}
}
// 多级反馈队列调度算法
void Scheduling::mfq()
{
int rd; // 随机数,随机产生新进程
int flag = 0; // flag标志是否有新进程进入初级队列
stime = 0; // 系统的时间
printf("-------多级反馈队列调度(时间片 = %d)-------\n\n", cap);
create_node();
// 遍历每个就绪队列
for (list<Node>::iterator iter = ln.begin(); iter != ln.end();)
{
printf("队列优先级 = %d 队列时间片 = %d\n", iter->priority, iter->cap);
// 遍历每个就绪队列的每个进程
while (!iter->q.empty())
{
// iter 指向当前队列; iter1 指向下一队列
list<Node>::iterator iter1 = iter;
Pro *p = &iter->q.front();
p->start_time = stime;
printf("进程PID=%d: 执行还需时间%d 开始执行时间%d ", p->pid, p->need_time, p->start_time);
// 进程无法在此队列一次完成
if (p->need_time > iter->cap)
{
// sleep(cap);
sleep(1);
p->need_time = p->need_time - cap;
p->end_time = cap;
p->run_time = p->run_time + cap;
stime = stime + cap;
++(p->count);
printf("第 %d 次执行,已执行时间 = %d\n", p->count, p->run_time);
if (++iter1 == ln.end()) // 如果当前进程正在最后一个队列
{
iter->q.push(iter->q.front());
iter->q.pop();
}
else // 把当前进程放到下一队列队尾
{
iter1->q.push(iter->q.front());
}
// 从当前队列移除
iter->q.pop();
}
else // 进程可以在此队列完成
{
// sleep(p->need_time);
sleep(1);
stime = stime + p->need_time;
p->end_time = stime;
p->run_time = p->run_time + p->need_time;
++(p->count);
printf("第 %d 次执行,已执行时间 = %d 结束时间 = %d 执行完毕\n", p->count, p->run_time, p->end_time);
p->end_time = 0;
iter->q.pop();
}
printf("\n");
rd = rand() % 10;
if (rd > 7 && pro_num < TOTAL_PRO_NUM) //有新进程进入高优先级队列
{
list<Node>::iterator iter2 = ln.begin();
Pro item;
item.pid = ++q_id;
item.count = 0;
item.need_time = rand() % 200 + 10; // 预计需求时间 在 10 ~ 100 之间
item.run_time = 0;
iter2->q.push(item);
pro_num++;
printf("创建进程 PID= %d: 执行所需时间 = %d\n", item.pid, item.need_time);
printf("\n");
if (iter2->priority < iter->priority) // 若当前队列优先级不是最高优先级
{
flag = 1;
break;
}
}
}
if (flag == 1)
{
iter = ln.begin();
}
else
{
++iter;
}
flag = 0;
}
}
int main(int argc, char const *argv[])
{
Scheduling sc;
sc.mfq();
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69751.html