死鎖詳解(預防,避免,檢測,解除)


     死鎖: 指多個進程/線程並發執行中,由於爭搶資源而造成的阻塞現象。

     產生死鎖的必要條件:   

        1.互斥:進程請求的資源是臨界資源

        2.請求並保持:進程占有了資源,並同時請求其他資源

        3.不可剝奪條件:進程占有的資源在未使用完之前,不可被剝奪

        4.環路等待

     解決死鎖的方法:

        預防死鎖: 破壞產生死鎖的條件

          資源一次性分配:一次性分配所有資源,這樣就不會再有請求了:(破壞請求條件)
          只要有一個資源得不到分配,也不給這個進程分配其他的資源:(破壞請保持條件)
          可剝奪資源:即當某進程獲得了部分資源,但得不到其它資源,則釋放已占有的資源(破壞不可剝奪條件)
          資源有序分配法:系統給每類資源賦予一個編號,每一個進程按編號遞增的順序請求資源,釋放則相反(破壞環路等待條件)

          1.碼上預防死鎖: 保證順序加鎖,比較mutex對象地址,始終先加鎖地址比較小的

          2.使用超時放棄機制

        避免死鎖: 銀行家算法

          預防死鎖的方法嚴重影響OS性能,所以使用銀行家算法避免死鎖。

          銀行家算法:

             (1) 可利用資源向量Available。這是一個含有m個元素的數組,其中的每一個元素代表一類可利用的資源數目。

                  (2) 最大需求矩陣Max。這是一個n×m的矩陣,它定義了系統中n個進程中的每一個進程對m類資源的最大需求。

                  (3) 分配矩陣Allocation。這也是一個n×m的矩陣,它定義了系統中每一類資源當前已分配給每一進程的資源數。

                                       (4) 需求矩陣Need。這也是一個n×m的矩陣,用以表示每一個進程尚需的各類資源數。

                  上述三個矩陣間存在下述關系:Allocation[i,j] + Need[i, j] = Max[i, j]  

             OS按照銀行家制定的規則為進程分配資源 --- 1.請求是否可以分配(<Max,<Avai) 2.分配資源,用安全性算法檢測

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

                 設 (1) 如果Requesti[j]≤Need[i,j],便轉向步驟(2);否則認為出錯,因為它所需要的資源數已超過它所宣布的最大值。

                   (2) 如果Requesti[j]≤Available[j],便轉向步驟(3);否則,表示尚無足夠資源,Pi須等待。

                      (3) 系統試探着把資源分配給進程Pi,並修改下面數據結構中的數值:
                      Available[j]:= Available[j]-Request i[j];
                      Allocation[i,j]:= Allocation[i,j]+Request i[j];
                      Need[i,j]:= Need[i,j]-Request i[j];

                   (4) 系統執行安全性算法檢查此次資源分配后系統是否處於安全狀態。若安全,才正式將資源分配給進程Pi,以完成本次分配;否則,將本次的試探分配作廢,恢復原來的資源分配狀態,讓進程Pi等待。

              安全性算法過程:

                   (1) 設置兩個向量:  
                        ① 工作向量Work,它表示系統可提供給進程繼續運行所需的各類資源數目,它含有m個元素,在執行安全算法開始時,Work=Available。  
                        ② Finish,它表示系統是否有足夠的資源分配給進程,使之運行完成。開始時先做Finish[i]=false;當有足夠資源分配給進程時,再令Finish[i]=true。
                   (2) 從進程集合中找到一個能滿足下述條件的進程:   
                        ① Finish[i]=false;  
                        ② Need[i,j]≤Work[j];若找到,執行步驟(3),否則,執行步驟(4)。
                   (3) 當進程Pi獲得資源后,可順利執行,直至完成,並釋放出分配給它的資源,故應執行:
                        Work[j]= Work[j]+Allocation[i,j];
                        Finish[i]=true;
                        go to step 2;
                   (4) 如果所有進程的Finish[i]=true都滿足,則表示系統處於安全狀態;否則,系統處於不安全狀態。

        檢查死鎖: 資源分配圖簡化法

           1.為每個進程,資源標識

            2.畫出資源分配和請求圖

              3.開始化簡資源分配圖,如果能化簡完所有箭頭,則表示無死鎖

        解除死鎖: 剝奪資源/銷毀進程

           1.剝奪其他線程資源,給死鎖進程用

           2.可以直接撤消死鎖進程或撤消代價最小的進程,直至有足夠的資源可用,死鎖狀態消除為止

        銀行家算法模擬實現:

#include<stdio.h>
#include <iostream>
#include<iomanip>
using namespace std;
#define MAXPROCESS 1000 /*最大進程數*/ 
#define MAXRESOURCE 1000 /*最大資源數*/ 

int AVAILABLE[MAXRESOURCE]; /*可用資源數組*/
int MAX[MAXPROCESS][MAXRESOURCE]; /*最大需求矩陣*/
int ALLOCATION[MAXPROCESS][MAXRESOURCE]; /*分配矩陣*/
int NEED[MAXPROCESS][MAXRESOURCE]; /*需求矩陣*/
int REQUEST[MAXPROCESS][MAXRESOURCE]; /*進程需要資源數*/
bool FINISH[MAXPROCESS]; /*系統是否有足夠的資源分配*/
int p[MAXPROCESS]; /*記錄序列*/
int m, n; /*m個進程,n個資源*/
int bank_flag = 0;/*標志是否有初始化資源*/

void Init();
bool Safe();
void Bank();
void Menu();
void Check();
void Show();

//主函數
int main()
{
	Menu();
}

//主界面
void Menu()
{
	while (1){
		printf("=========================\n");
		printf("*      銀行家算法       *\n");
		printf("*     1.設置資源初值    *\n");
		printf("*     2.安全性檢測      *\n");
		printf("*     3.申請資源        *\n");
		printf("*     4.顯示資源        *\n");
		printf("*     0.退出            *\n");
		printf("=========================\n");
		printf("請輸入您的選項:");
		int choice = 0;
		cin >> choice;
		switch (choice)
		{
		case 1:
			Init();
			break;
		case 2:
			Safe();
			break;
		case 3:
			Bank();
			break;
		case 4:
			Show();
			break;
		case 0:
			return;
		default:
			cout << "輸入非法,請重新輸入!" << endl;
		}
	}
}

//展示資源
void Show()
{
	if (bank_flag == 0)
	{
		cout << "請設置資源初值!" << endl;
		cout << endl;
		return;
	}
	//設置左對齊
	cout << setiosflags(ios::left);
	int w = 18;
	cout << setw(w) << "Pid";
	cout << setw(w) << "Max";
	cout << setw(w) << "Allocation";
	cout << setw(w) << "Need";
	cout << setw(w) << "Available" << endl;

	for (int i = 0; i < m; i++)
	{
		cout << setw(15) << i;
		int wid = 18 / n;
		for (int j = 0; j < n; j++)
		{
			cout << setw(wid) << MAX[i][j];
		}
		cout << " ";
		for (int j = 0; j < n; j++)
		{
			cout << setw(wid) << ALLOCATION[i][j];
		}
		cout << " ";
		for (int j = 0; j < n; j++)
		{
			cout << setw(wid) << NEED[i][j];
		}
		cout << " ";
		if (i == 0)
		{
			for (int z = 0; z < n; z++){
				cout << setw(wid) << AVAILABLE[z];
			}
		}
		cout << endl;
	}
	cout << endl;
}

//回退步驟
bool Check(int flag)
{
	return flag ==  -1? true : false;
}
//初始化
void Init() 
{
	cout << "如需回到主界面,輸入-1" << endl;
	int i, j;
	cout << "請輸入進程的數目:";
	cin >> m;
	if (Check(m))
		return;

	cout << "請輸入資源的種類:";
	cin >> n;
	if (Check(n))
		return;

	cout << "請輸入每個進程最多所需的各資源數,按照" << m << "x" << n << "矩陣輸入" << endl;
	for (i = 0; i < m; i++){
		for (j = 0; j < n; j++){
			cin >> MAX[i][j];
			if (Check(MAX[i][j]))
				return;
		}
	}

	cout << "請輸入每個進程已分配的各資源數,也按照" << m << "x" << n << "矩陣輸入" << endl;
	for (i = 0; i<m; i++)
	{
		for (j = 0; j<n; j++)
		{
			cin >> ALLOCATION[i][j];
			NEED[i][j] = MAX[i][j] - ALLOCATION[i][j];

			if (Check(ALLOCATION[i][j]))
				return;
			if (NEED[i][j]<0)
			{
				cout << "您輸入的第" << i + 1 << "個進程所擁有的第" << j + 1 << "個資源數錯誤,請重新輸入:" << endl;
				j--;
				continue;
			}
		}
	}
	cout << "請輸入各個資源現有的數目:" << endl;
	for (i = 0; i<n; i++)
	{
		cin >> AVAILABLE[i];
		if (Check(AVAILABLE[i]))
			return;
	}
	bank_flag = 1; //資源初始化成功標志
	cout << endl;
}

//銀行家算法
void Bank() 
{
		if (bank_flag == 0)
		{
			cout << "請設置資源初值!" << endl;
			cout << endl;
			return;
		}
		int i, cusneed;

		int flag = 0;//銀行家算法4步驟成功標志
		
		//請求資源初始化
		cout << "請輸入要申請資源的進程號(下標從0開始):";
		cin >> cusneed;
		cout << "請輸入進程所請求的各資源的數量:";
		for (i = 0; i<n; i++)
		{
			cin >> REQUEST[cusneed][i];
		}

		//1.request[i][j]<=need[i][j]
		//2.request[i][j]<=aval[i][j]
		for (i = 0; i<n; i++)
		{
			if (REQUEST[cusneed][i]>NEED[cusneed][i])
			{
				cout << "請求數超過進程的需求量!" << endl;
				flag = 1;
				break;
			}
			if (REQUEST[cusneed][i]>AVAILABLE[i])
			{
				cout << "請求數超過系統有的資源數!" << endl;
				flag = 1;
				break;
			}
		}
		if (flag == 1)
			return;

		//3.試圖分配
		//現有資源-req;i分配資源+req;i需求-req;
		for (i = 0; i<n; i++)
		{
			AVAILABLE[i] -= REQUEST[cusneed][i];
			ALLOCATION[cusneed][i] += REQUEST[cusneed][i];
			NEED[cusneed][i] -= REQUEST[cusneed][i];
		}
		//4.安全性算法
		if (Safe())
		{
			cout << "同意分配請求!" << endl;
		}
		else
		{
			//請求拒絕,還原資源
			cout << "請求被拒絕!" << endl;
			for (i = 0; i<n; i++)
			{
				AVAILABLE[i] += REQUEST[cusneed][i];
				ALLOCATION[cusneed][i] -= REQUEST[cusneed][i];
				NEED[cusneed][i] += REQUEST[cusneed][i];
			}
		}
		//將完成標志重置為false
		for (i = 0; i<m; i++)
		{
			FINISH[i] = false;
		}
	
		cout << endl;
}

//安全性算法
bool Safe() 
{
	if (bank_flag == 0)
	{
		cout << "請設置資源初值!" << endl;
		cout << endl;
		return false;
	}

	int i, j, k, l = 0;
	int Work[MAXRESOURCE]; //工作數組

	for (i = 0; i<n; i++)  //初始化work
		Work[i] = AVAILABLE[i];
	for (i = 0; i<m; i++)
	{
		FINISH[i] = false;
	}

	for (i = 0; i<m; i++)
	{
		//進程資源已回收,找下一個
		if (FINISH[i] == true)
		{
			continue;
		}
		//進程資源未會回收
		else
		{
			//work[j]<need[i][j],不滿足
			for (j = 0; j<n; j++)
			{
				if (NEED[i][j]>Work[j])
				{
					break;
				}
			}
			//work[j]>need[i][j],回收此進程資源
			if (j == n)
			{
				FINISH[i] = true;
				for (k = 0; k<n; k++)
				{
					Work[k] += ALLOCATION[i][k];
				}
				//回收的進程放入記錄序列
				p[l++] = i;
				//重頭繼續找
				i = -1;
			}
			else
			{
				continue;
			}
		}
		//如果進程全部完成,則返回安全對列
		if (l == m)
		{
			cout << "系統是安全的" << endl;
			cout << "安全序列:" ;
			for (i = 0; i<l; i++)
			{
				cout << p[i];
				if (i != l - 1)
				{
					cout << "-->";
				}
			}
			cout << "" << endl;
			cout << endl;
			return true;
		}
	}//end of for

	//進程有未完成的,不安全
	cout << "系統是不安全的" << endl;
	cout << endl;
	return false;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM