死結

循環等待(circular wait)

想像四個小孩各拿一顆球,圍坐成一圈。每個小孩都說:「你把你的球給我,我就馬上把我的給你」——但他是對左邊的小孩說,卻指望右邊的小孩給。繞著整個圈,每個人都在等下一個人,這條鏈又閉合回自己,於是誰也不會把任何東西交出去。這個互相等待的封閉迴圈就是循環等待。

循環等待是死結的第四個必要條件,直覺上也是「封住」陷阱的那一個。當存在一組等待中的行程 P1、P2、……、Pn,使得 P1 等著 P2 持有的資源、P2 等著 P3 持有的、依此類推,而 Pn 等著 P1 持有的資源——形成一個環——這個條件就成立。在資源配置圖裡,這就是穿過行程與資源的一圈邊所構成的環。經典的預防法是對所有資源類型施加一個全序(total ordering)——把它們編號 1、2、3、……——並要求每個行程只能依遞增的編號順序取得資源。如此就絕不會形成環,因為環會需要某個行程在持有編號較高的資源時去請求編號較低的,而規則正禁止這件事。

鎖定排序(lock-ordering)是這個想法在日常中的實用版本,也是並行程式碼裡對抗死結最常見的真實防線:為你的鎖約定一個全域順序,並永遠依此順序取鎖。誠實的告誡有兩點。第一,這個順序必須是全域且一致的——只要有一個函式以錯誤順序取鎖,就可能重新引入一個環。第二,等待圖中的環只有在單一實例資源下才保證是死結;對多實例資源,環是必要而非充分的,因為某個多餘的實例可能打斷那條鏈。

沒有排序時:執行緒 X 做 lock(A); lock(B),而執行緒 Y 做 lock(B); lock(A)——可能形成環。有排序時(永遠先 A 後 B):兩者都做 lock(A); lock(B),於是誰都不會在等 A 時還持有 B,環就無法形成。

對資源施加全域的取得順序,使循環等待不可能發生。

只有當每種資源都是單一實例時,等待圖中的環才保證是死結;多實例時環是必要而非充分的。排序防線若未全域且一致地施行就會失效。

又称
cyclic waitwait cycle等待環