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