死鎖: 指多個進程/線程並發執行中,由於爭搶資源而造成的阻塞現象。
產生死鎖的必要條件:
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;
}
