有限等待(bounded waiting)
假設廁所規則精神上是公平的——誰有空誰就進去——但實際上,每次你伸手要開門,總有手腳更快的人擠到你前面,一次又一次,你就在那兒站上好幾個鐘頭。進展技術上是滿足的(有人在等時房間從不閒置),可是偏偏你這個人始終進不去。有限等待正是修正這件事的要求:一條執行緒提出進入臨界區間的請求之後,其他執行緒能搶在它前面進入的次數有一個固定上限,超過這個上限,它的請求就必須被准許。
關鍵詞是「有限」。有限等待並不保證你是下一個,也不保證任何特定的速度;它只保證你被超車的次數是有限且事先已知的——例如對 n 條執行緒而言,至多被超 n-1 次。一旦達到那個上限,就必須輪到你。這正是排除「飢餓」的保證:飢餓就是某條倒楣執行緒永遠等待,而源源不絕的其他執行緒一直插隊。許多看起來簡單又正確的鎖,提供了互斥與進展,卻在高度爭用時悄悄允許了無上限的超車。
有限等待是三項臨界區間要求中第三項、也最微妙的一項,而且是代價最高的一項。要保證它,通常得讓進入協定記住誰在等、並強制某種順序——一個佇列、一個號碼牌、一輪輪轉。普通的自旋鎖與簡單的測試並設定鎖,本身通常不保證有限等待:在爭用下,同一條幸運的執行緒可能一再搶到鎖。較公平的構造(號碼牌鎖、以佇列為基礎的鎖、公平互斥鎖)正是加上這些記帳,才換得這項保證,用一點點速度換來「沒有人永遠等待」的承諾。
號碼牌鎖就像熟食店的取號機:每條到達的執行緒抽下一個號碼,而鎖嚴格按號碼順序授予。無論別人來得多頻繁,持有 47 號的執行緒最多只等在 45、46 號之後——一個硬性的上限——所以它永遠不會被餓死。
有限等待限制了你能被超車的次數——這正是消滅飢餓的關鍵。
普通的測試並設定鎖/自旋鎖本身並不保證有限等待;在爭用下某一條執行緒可能一直獲勝。公平性必須刻意加上(例如號碼牌或佇列)。