1.死鎖檢測
給定一組線程操作鎖的流程,判斷是否會發生死鎖?
例如:有兩個線程和兩個資源,線程對鎖的操作如下:
其中T表示線程id,L表示鎖id,S表示操作(1表示獲取鎖,0表示釋放鎖)
T L S
1 1 1(線程1獲取1號鎖)
2 2 2(線程2獲取2號鎖)
1 2 1(線程1獲取2號鎖,保持等待)
2 1 1(線程2獲取1號鎖,導致死鎖)
如果最后一次操作換為:2 2 0,就不會死鎖.
問題的關鍵是如何判斷死鎖的發生,以上面的例子為例:線程2獲取1號鎖時,發現1號鎖被1號線程占用,那么就要等待線程1釋放1號鎖,然后再看線程1在等待2號鎖,2號鎖被2號線程占用,因此1號線程又要等2號線程釋放2號鎖,這就形成了一個等待環:線程2->線程1->線程2,發生死鎖.所以檢測死鎖的方法就是判斷是否存在這種等待的環路.
對於給定的線程操作鎖的序列:vector<vector<int>> tls,判斷是否發生死鎖要維護3個map,
map<int, int> lock2thread:鎖->線程,標識當前鎖被哪個線程占用
map<int, int> waitedthread2lock:標識當前線程在等待哪個鎖
map<int, vector<int>> thread2locks:標識線程持有的鎖.
偽代碼如下(省去了一些更新和查詢操作):
bool DeadLock(vector<vector<int>> &tls) { int size = tls.size(); map<int, int> lock2thread; map<int, int> waitedthread2lock; map<int, vector<int>> thread2locks; for(int i = 0; i < size; i++) { int tid = tls[i][0]; int lock = tls[i][1]; int state = tls[i][2]; if (state == 0) { //釋放鎖,這是一定不會引起死鎖的,因此只需要更新3個map就可以了 //1.從lock2thread中刪除key==lock的元素 lock2thread.erase(lock2thread.find(lock)); //2.從thread2locks中移除lock thread2locks[tid].erase(find(thread2locks[tid].begin(), thread2locks[tid].end(),lock)); //3.遍歷waitedthread2lock,查看哪個線程等待lock //3.1如果有線程等待此lock,那么依次更新lock2thread和thread2locks } else { //說明tid想要獲取lock,那么這個操作是可能導致死鎖的 if (lock2thread.find(lock) != lock2thread.end()) { //說明該鎖已經被占用,那么可能引起死鎖 int nexttid = 0;//當前線程依賴的下一個線程 int nextlock = lock; while(1) { nexttid = lock2thread[nextlock]; if (nexttid == tid) return true;//發生死鎖 //查看nexttid在等待哪個資源 if (waitedthread2lock.find(nexttid) != waitedthread2lock.end()) { nextlock = waitedthread2lock[nexttid]; } else { //說明沒有環路,不發生死鎖 更新waitedthread2lock; break; } } } else { //說明lock空閑,直接獲取 更新lock2thread和thread2locks; } } } }
2.死鎖預防:銀行家算法
思路很簡單,只有當資源池中有充足的資源時才將資源分配給進程,否則便認為可能存在死鎖的風險.
具體可參考這篇簡單明了的文章:https://zhuanlan.zhihu.com/p/59533950