【計算機操作系統】銀行家算法和安全性算法的 C++ 實現(附源碼)

一、實驗目的

  用高級語言編寫和調試一個或多個作業調度的模擬程序,以加深對作業調度算法的理解。因爲源碼中我對一些關鍵步驟的註釋已經比較清晰了,所以在本文中不會再對每一個細節都進行分析,只分析整體的代碼結構和所使用到的設計模式。

  博客內所有文章均爲 原創,所有示意圖均爲 原創,若轉載請附原文鏈接。

二、實驗內容

2.1 數據結構

  • 1.可利用資源向量 Available ,它是一個含有 m 個元素的數組,其中的每一個元素代表一類可利用的資源的數目,其初始值是系統中所配置的該類全部可用資源數目。其數值隨該類資源的分配和回收而動態地改變。如果Available(j) = k,表是系統中現有Rj類資源k個。

  • 2.最大需求矩陣 Max,這是一個n×m的矩陣,它定義了系統中 n 個進程中的每一個進程對 m 類資源的最大需求。如果Max(i,j) = k,表示進程 i 需要 Rj 類資源的最大數目爲 k 。

  • 3.分配矩陣 Allocation,這是一個 n×m 的矩陣,它定義了系統中的每類資源當前一分配到每一個進程的資源數。如果 Allocation(i,j) = k,表示進程 i 當前已經分到 Rj 類資源的數目爲 k 。Allocationi 表示進程i的分配向量,有矩陣 Allocation 的第 i 行構成。

  • 4.需求矩陣 Need,這是一個 n×m 的矩陣,用以表示每個進程還需要的各類資源的數目。如果Need(i,j) = k,表示進程i還需要 Rj 類資源 k 個,才能完成其任務。Needi 表示進程i的需求向量,由矩陣 Need 的第 i 行構成。

  • 上述三個矩陣間存在關係:Need(i,j) = Max(i,j) - Allocation(i,j);

2.2 銀行家算法

  設 Requesti 是進程 Pi 的請求向量,如果 Requesti[j] = K,表示進程 Pi 需要 K 個 Pj 類型的資源。當 Pi 發出自願請求後,系統按下述步驟進行檢查:

  • (1)如果 Requesti[j] <= Need[i,j],便轉向步驟(2);否則認爲出錯,因爲它所需要的資源數已超過它所宣佈的最大值。
  • (2)如果Requesti[j] <= Available[j],便轉向步驟(3);否則,表示尚無足夠資源,Pi 需等待。
  • (3)系統試探着把資源分配給進程 Pi,並修改下面數據結構中的數值:
    Available[j] = Available[j] - Requesti[j];
    Allocation[i,j] = Allocation + Requesti[j];
    Need[i,j] = Need[i,j] - Requesti[j];
  • (4)系統執行安全性算法,檢查此次資源分配後系統是否處於安全狀態。若安全,才正式將資源分配給進程 Pi,以完成本次分配;否則,將本次的試探性分配作廢,恢復原來的資源分配狀態,讓進程 Pi 等待。

2.3 安全性算法

  • 1.設置兩個向量。
    Work:它表示系統可提供給進程繼續運行的各類資源數目,它包含m個元素,開始執行安全性算法時,Work = Available。
    Finish:它表示系統是否有足夠的資源分配給進程,使之運行完成,開始Finish(i)=false;當有足夠資源分配給進程Pi時,令Finish(i)=true;

  • 2.從進程集合中找到一個能滿足下述條件的進程。
    Finish(i) == false;
    Need i ≤ work;
    如找到則執行步驟3;否則,執行步驟4;

  • 3.當進程 Pi 獲得資源後,可順利執行直到完成,並釋放出分配給它的資源,故應執行
    Work = work + Allocation i
    Finish(i) = true;轉向步驟2;

  • 4.若所有進程的 Finish(i) 都爲true,則表示系統處於安全狀態;否則,系統處於不安全狀態。

三、流程圖

3.1 單道批處理系統的作業調度

在這裏插入圖片描述

四、代碼實現

#include <iostream>
#include <vector>

typedef std::vector<int> Resource;
typedef std::vector<int> * ResourcePtr;
typedef std::vector<std::vector<int>> Resources;
typedef std::vector<std::vector<int>> * ResourcesPtr;

class BankerAlgorithm
{
public:
	BankerAlgorithm()
	{
		/*
		process_num_ = process_num;
		resource_num_ = resource_num;
		*/

		// should input by  user
		//available_ = new std::vector<int>(resource_num, 0);
		/*
		(*available_)[0] = 3;
		(*available_)[1] = 3;
		(*available_)[2] = 2;
		*/

		//allocation_ = createResourceArray(process_num, resource_num);
		//need_ = createResourceArray(process_num, resource_num);

		/*
		(*need_)[0][0] = 7; (*need_)[0][1] = 4; (*need_)[0][2] = 3;
		(*need_)[1][0] = 1; (*need_)[1][1] = 2; (*need_)[1][2] = 2;
		(*need_)[2][0] = 6; (*need_)[2][1] = 0; (*need_)[2][2] = 0;
		(*need_)[3][0] = 0; (*need_)[3][1] = 1; (*need_)[3][2] = 1;
		(*need_)[4][0] = 4; (*need_)[4][1] = 3; (*need_)[4][2] = 1;

		(*allocation_)[0][0] = 0; (*allocation_)[0][1] = 1; (*allocation_)[0][2] = 0;
		(*allocation_)[1][0] = 2; (*allocation_)[1][1] = 0; (*allocation_)[1][2] = 0;
		(*allocation_)[2][0] = 3; (*allocation_)[2][1] = 0; (*allocation_)[2][2] = 2;
		(*allocation_)[3][0] = 2; (*allocation_)[3][1] = 1; (*allocation_)[3][2] = 1;
		(*allocation_)[4][0] = 0; (*allocation_)[4][1] = 0; (*allocation_)[4][2] = 2;
		*/
	}

	inline ResourcesPtr createResourceArray(int row_num, int col_num)
	{
		return new std::vector<std::vector<int>>(row_num, std::vector<int>(col_num, 0));
	}

	inline ResourcesPtr copyResourceArray(ResourcesPtr ori)
	{
		int col_num = (*ori)[0].size();
		int row_num = (*ori).size();
		ResourcesPtr res = createResourceArray(row_num, col_num);
		for (int i = 0; i < row_num; ++i)
			for (int j = 0; j < col_num; ++j)
				(*res)[i][j] = (*ori)[i][j];
		return res;
	}

	bool inputInitData()
	{
		std::cout << "please input process num and resource num: " << std::endl;
		std::cin >> process_num_ >> resource_num_;

		// allocate memory for struct
		available_ = new std::vector<int>(resource_num_, 0);
		allocation_ = createResourceArray(process_num_, resource_num_);
		need_ = createResourceArray(process_num_, resource_num_);

		std::cout << "please input init resource: " << std::endl;
		for (int i = 0; i < resource_num_; ++i)
			std::cin >> (*available_)[i];

		std::cout << "please input max matrix: " << std::endl;
		ResourcesPtr max = createResourceArray(process_num_, resource_num_);
		bool inputSuccess = true;
		do {
			inputSuccess = true;
			for (int i = 0; i < process_num_; ++i)
			{
				for (int j = 0; j < resource_num_; ++j)
				{
					std::cin >> (*max)[i][j];
					if ((*max)[i][j] > (*available_)[j])
					{
						inputSuccess = false;
						max->clear();
						std::cout << "max matrix is illegal, please reinput max matrix: " << std::endl;
						break;
					}
				}
			}
		} while (!inputSuccess);


		std::cout << "please input allocation matrix: " << std::endl;
		for (int i = 0; i < process_num_; ++i)
		{
			for (int j = 0; j < resource_num_; ++j)
			{
				std::cin >> (*allocation_)[i][j];
				(*need_)[i][j] = (*max)[i][j] - (*allocation_)[i][j];
				(*available_)[j] -= (*allocation_)[i][j];
			}
		}
		std::cout << "current available resource: [";
		for (int num : *available_)
			std::cout << num << " ";
		std::cout << "]" << std::endl;

		std::vector<int> * req = new std::vector<int>(resource_num_, 0);
		if (!bankerAlgorithm(-1, req))
		{
			std::cout << "init fail, data is illegal!" << std::endl;
		}

		bool quit = false;
		while (!quit)
		{
			std::cout << "please input request process: " << std::endl;
			int pid = -1;
			std::cin >> pid;

			std::cout << "please input request resource: " << std::endl;
			for (int i = 0; i < resource_num_; ++i)
				std::cin >> (*req)[i];

			// do allocate.
			bankerAlgorithm(pid, req);
		}
	}

	inline bool allocateResourcesForProcess(int pid, ResourcePtr request)
	{
		return bankerAlgorithm(pid, request);
	}

	bool bankerAlgorithm(int pid, ResourcePtr request)
	{
		for (int i = 0; pid != -1 && i < (*request).size(); ++i)
		{
			if ((*request)[i] > (*need_)[pid][i])
			{
				std::cout << "[ERROR] request Resource more than need ResourcePtr." << std::endl;
				return false;
			}
			else if ((*request)[i] > (*available_)[i])
			{
				std::cout << "[ERROR] request Resource more than available ResourcePtr." << std::endl;
				return false;
			}
		}

		// Here the copied value is passed
		if (securityAlgorithm(pid, *available_, *request, *need_, *allocation_))
		{
			std::cout << "[INFO] securityAlgorithm true" << std::endl;

			// Really allocate resources to process
			for (int i = 0; pid != -1 && i < (*request).size(); ++i)
			{
				(*available_)[i] -= (*request)[i];
				(*allocation_)[pid][i] += (*request)[i];
				(*need_)[pid][i] -= (*request)[i];
			}
			// Debug
			printResources();
			return true;
		}
		else
		{
			std::cout << "[INFO] securityAlgorithm false" << std::endl;
			// Don't allocate resources to process
			// Debug
			printResources();
			return false;
		}
	}

	bool securityAlgorithm(int pid, Resource available, Resource request, Resources need, Resources allocation)
	{
		if (pid != -1)
		{
			for (int i = 0; i < request.size(); ++i)
			{
				available[i] -= request[i];
				allocation[pid][i] += request[i];
				need[pid][i] -= request[i];
			}
		}

		Resource work(available);
		std::vector<bool> finish(allocation.size(), false);

		while ((pid = getUsableProcessForSecurityAlgorithm(finish, work, need)) != -1)
		{
			for (int i = 0; i < work.size(); ++i)
				work[i] += allocation[pid][i];
			finish[pid] = true;

			std::cout << "[INFO] process " << pid << " finish true, work: [";
			for (int num : work)
				std::cout << num << " ";
			std::cout << "]" << std::endl;

		}

		for (bool b : finish)
			if (!b) return false;
		return true;
	}

	// return pid
	int getUsableProcessForSecurityAlgorithm(std::vector<bool> finish, Resource work, Resources need)
	{
		for (int pid = 0; pid < finish.size(); ++pid)
		{
			if (!finish[pid])
			{
				bool canUse = true;
				for (int i = 0; i < work.size(); ++i)
				{
					if (need[pid][i] > work[i])
					{
						canUse = false;
						break;
					}
				}
				if (canUse) return pid;
			}
		}
		return -1;
	}

	bool printResources()
	{
		std::cout << "available: " << std::endl;
		for (int num : *available_)
			std::cout << num << " ";
		std::cout << std::endl << std::endl;

		std::cout << "allocation: " << std::endl;
		printResource(allocation_);
		std::cout << std::endl;

		std::cout << "need: " << std::endl;
		printResource(need_);
		std::cout << std::endl;
	}

	bool printResource(ResourcesPtr ResourcesPtr)
	{
		for (std::vector<int> vec : *ResourcesPtr)
		{
			for (int num : vec)
				std::cout << num << " ";
			std::cout << std::endl;
		}
		return true;
	}

private:
	int process_num_;
	int resource_num_;

	ResourcePtr available_;
	ResourcesPtr allocation_;
	ResourcesPtr need_;
};

五、運行結果

5.1 初始化

在這裏插入圖片描述

5.2 驗證初始化狀態的安全性

在這裏插入圖片描述

5.3 進程1請求資源 1 0 2 並通過安全性檢查,分配給它資源

在這裏插入圖片描述

5.4 進程4請求資源 3 3 0 並因爲其請求資源大於Available資源,因此讓進程4等待

在這裏插入圖片描述

5.5 進程0請求資源 0 2 0 並因爲進行安全性檢查時不存在安全序列,因此不分配資源

在這裏插入圖片描述

5.6 進程0請求資源 0 1 0 並因爲符合安全性檢查,存在安全隊列,因此分配資源

在這裏插入圖片描述

六、結尾

  如果本文描述的內容或使用的代碼存在任何問題,請及時聯繫我或在本篇文章的下面進行評論,我會本着對每一位學技術同學的負責態度立即修改。在後續還會有三篇計算機操作系統的算法 C++ 復現博文,如果感興趣可以關注我。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章