多級反饋佇列排程演算法(MFQ)

AHU_Tree發表於2015-12-09

多級反饋佇列排程演算法是目前公認的較好的一種程式排程演算法,它能較好的滿足各類程式的需要。


MFQ演算法首先設定多個就緒佇列。佇列的優先順序遞減,且各佇列時間片大小也不同。例如我實現的演算法裡,設定了3個佇列,第一佇列優先順序>第二佇列>第三佇列,且後一個佇列的時間片大小是前一個的2倍。

每個佇列都採用FCFS策略排列。首先排程高優先順序佇列內的程式,如果此程式在時間片內不能執行完,則將它加入下一個佇列。這樣到了最後一個佇列,就成了RR演算法。

如果有高優先順序的程式到達,則放棄正在排程的程式,轉向排程最高優先順序的程式。這裡我的實現不是很完美,我的演算法裡當高優先順序程式到達時,如果有程式正在執行,則需要等到這個程式時間片結束才能轉到高優先順序程式。需要進一步修改,今晚困了,改不動了




//main.cpp
#include "MFQ.h"

int main()
{
	std::vector<PCB> PCBList;
	int timeslice;

	//輸入時間片大小,作業資訊
	InputPCB(PCBList, timeslice);

	//MFQ演算法
	MFQ(PCBList, timeslice);

	//顯示結果
	show(PCBList);

	return 0;
}

//MFQ.h
#ifndef MFQ_H_
#define MFQ_H_

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <queue>

//作業結構體
typedef struct PCB
{
	int ID;							//識別符號
	int ComeTime;					//到達時間
	int ServerTime;					//服務時間
	int FinishTime;					//完成時間
	int TurnoverTime;				//週轉時間
	double WeightedTurnoverTime;	//帶權週轉時間
}PCB;

/*
函式功能:輸入作業資訊
引數說明:
PCBList		std::vector<PCB>&		PCB鏈
timeslice	int						第一佇列時間片
*/
void InputPCB(std::vector<PCB> &PCBList, int ×lice);

/*
函式功能:MFQ演算法
引數說明:
PCBList		std::vector<PCB>&		PCB鏈
timeslice	int						第一佇列時間片
*/
void MFQ(std::vector<PCB> &PCBList, int timeslice);

/*
函式功能:顯示結果
引數說明:
PCBList		std::vector<PCB>&		PCB鏈
*/
void show(std::vector<PCB> &PCBList);

/*
函式功能:比較函式,用於sort(),按ComeTime升序排列
引數說明:
p1			const PCB&				PCB
p2			const PCB&				PCB
*/
bool CmpByComeTime(const PCB &p1, const PCB &p2);

#endif

//MFQ.cpp
#include "MFQ.h"

//輸入作業資訊
void InputPCB(std::vector<PCB> &PCBList, int ×lice)
{
	std::cout << "輸入第一佇列時間片大小: ";
	std::cin >> timeslice;
	do {
		PCB temp;
		std::cout << "輸入識別符號: ";
		std::cin >> temp.ID;
		std::cout << "輸入到達時間: ";
		std::cin >> temp.ComeTime;
		std::cout << "輸入服務時間: ";
		std::cin >> temp.ServerTime;
		temp.FinishTime = 0;		//暫時存放執行了多少時間,來判斷此作業是否執行結束
		PCBList.push_back(temp);

		std::cout << "繼續輸入?Y/N: ";
		char ans;
		std::cin >> ans;
		if ('Y' == ans || 'y' == ans)
			continue;
		else
			break;
	} while (true);
}

//MFQ演算法
void MFQ(std::vector<PCB> &PCBList, int timeslice)
{
	std::sort(PCBList.begin(), PCBList.end(), CmpByComeTime);		//按到達時間排序
	std::vector<PCB> result;	//儲存結果
	int BeginTime = (*PCBList.begin()).ComeTime;					//第一個作業開始時間
	const int QueueNum = 3;
	std::queue<PCB> Ready[QueueNum];		//設定3個就緒佇列
	Ready[0].push(*PCBList.begin());
	PCBList.erase(PCBList.begin());

	while (!PCBList.empty())
	{
		//這段是為了防止前面的程式執行完了,後面的程式還沒到,造成死迴圈
		bool flag = false;
		for (int i = 0; i < QueueNum; ++i)
		{
			if (!Ready[i].empty())
			{
				flag = true;
				break;
			}
		}
		if(!flag)
		{
			Ready[0].push(*PCBList.begin());
			PCBList.erase(PCBList.begin());
			BeginTime = Ready[0].front().ComeTime;
		}

		for (int i = 0; i < QueueNum; ++i)
		{ 
			int times = timeslice * (i + 1);		//下一個佇列的時間片大小是上一個的2倍
			if (i != QueueNum - 1)		//不是最後一個佇列
			{
				while (!Ready[i].empty())		//佇列不空
				{
					if (!PCBList.empty() && BeginTime >= (*PCBList.begin()).ComeTime)	//有新作業到達,加入就緒佇列,轉到第一佇列
					{
						Ready[0].push(*PCBList.begin());
						PCBList.erase(PCBList.begin());
						i = 0; 
						continue;
					}

					if (Ready[i].front().FinishTime + times < Ready[i].front().ServerTime)		//時間片用完沒執行完,加入下一佇列隊尾
					{
						Ready[i].front().FinishTime += times;
						Ready[i + 1].push(Ready[i].front());
						Ready[i].pop();
						BeginTime += times;
					}
					else		//此作業執行完
					{
						BeginTime += Ready[i].front().ServerTime - Ready[i].front().FinishTime;
						Ready[i].front().FinishTime = BeginTime;
						Ready[i].front().TurnoverTime = Ready[i].front().FinishTime - Ready[i].front().ComeTime;
						Ready[i].front().WeightedTurnoverTime = (double)Ready[i].front().TurnoverTime / Ready[i].front().ServerTime;

						//從就緒佇列中移除作業
						result.push_back(Ready[i].front());
						Ready[i].pop();
					}
				}
			}
			else
			{
				while (!Ready[i].empty())
				{
					if (!PCBList.empty() && BeginTime >= (*PCBList.begin()).ComeTime)	//有新作業到達,加入就緒佇列,轉到第一佇列
					{
						Ready[0].push(*PCBList.begin());
						PCBList.erase(PCBList.begin());
						i = -1;
						break;
					}
					if (Ready[i].front().FinishTime + times < Ready[i].front().ServerTime)		//時間片用完沒執行完,加入隊尾
					{
						Ready[i].front().FinishTime += times;
						Ready[i].push(Ready[i].front());
						Ready[i].pop();
						BeginTime += times;
					}
					else		//此作業執行完
					{
						BeginTime += Ready[i].front().ServerTime - Ready[i].front().FinishTime;
						Ready[i].front().FinishTime = BeginTime;
						Ready[i].front().TurnoverTime = Ready[i].front().FinishTime - Ready[i].front().ComeTime;
						Ready[i].front().WeightedTurnoverTime = (double)Ready[i].front().TurnoverTime / Ready[i].front().ServerTime;

						//從就緒佇列中移除作業
						result.push_back(Ready[i].front());
						Ready[i].pop();
					}
				}
			}
		}
	}

	//按ComeTime升序排序,便於顯示結果
	PCBList = result;
	std::sort(PCBList.begin(), PCBList.end(), CmpByComeTime);
}

//顯示結果
void show(std::vector<PCB> &PCBList)
{
	int SumTurnoverTime = 0;
	double SumWeightedTurnoverTime = 0;

	std::cout.setf(std::ios::left);
	std::cout.precision(2);

	std::cout << std::setw(20) << "識別符號";
	for (std::vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it)
		std::cout << std::setw(5) << (*it).ID;
	std::cout << std::endl;

	std::cout << std::setw(20) << "到達時間";
	for (std::vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it)
		std::cout << std::setw(5) << (*it).ComeTime;
	std::cout << std::endl;

	std::cout << std::setw(20) << "服務時間";
	for (std::vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it)
		std::cout << std::setw(5) << (*it).ServerTime;
	std::cout << std::endl;

	std::cout << std::setw(20) << "完成時間";
	for (std::vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it)
		std::cout << std::setw(5) << (*it).FinishTime;
	std::cout << std::endl;

	std::cout << std::setw(20) << "週轉時間";
	for (std::vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it)
	{
		std::cout << std::setw(5) << (*it).TurnoverTime;
		SumTurnoverTime += (*it).TurnoverTime;;
	}
	std::cout << std::endl;

	std::cout << std::setw(20) << "帶權週轉時間";
	for (std::vector<PCB>::iterator it = PCBList.begin(); it < PCBList.end(); ++it)
	{
		std::cout << std::setw(5) << (*it).WeightedTurnoverTime;
		SumWeightedTurnoverTime += (*it).WeightedTurnoverTime;;
	}
	std::cout << std::endl;

	std::cout << "平均週轉時間: " << (double)SumTurnoverTime / PCBList.size() << std::endl;
	std::cout << "平均帶權週轉時間: " << SumWeightedTurnoverTime / PCBList.size() << std::endl;
}

//比較函式,按ComeTime升序排列
bool CmpByComeTime(const PCB &p1, const PCB &p2)
{
	return p1.ComeTime < p2.ComeTime;
}


相關文章