行程同步與臨界區間問題

忙碌等待(busy waiting)

等一件事有兩種方式。一種是不停地、用最快的速度反覆查看:「好了沒?好了沒?好了沒?」另一種是去睡覺,並請別人在好了的時候叫醒你。忙碌等待是第一種。一條無法前進的執行緒待在一個緊湊迴圈裡,反覆測試某個條件,整段時間都在耗 CPU,卻什麼也沒完成。這就像站在微波爐前一遍遍戳開門鈕,而不是走開、等嗶聲再回來。

具體來說,忙碌等待長得像 while (locked) { /* 什麼都不做,再查一次 */ }。執行緒從不交出 CPU;它就只是在測試上自旋。好處是反應快、每次嘗試的開銷低:條件一翻轉,自旋的執行緒立刻就察覺,省去了「睡著再被喚醒」的成本(一次睡眠/喚醒牽涉到進入核心再返回的環境切換,可能比自旋本身久得多)。所以若你等的東西會在幾百奈秒內變成真——例如一把只被另一顆正在執行的核心短暫持有的鎖——自旋可能是最快的選擇。

壞處是浪費,而且可能很嚴重。當一條執行緒忙碌等待時,它佔著一顆 CPU 核心,做的事字面上是零,等於把那顆核心從本可前進的執行緒手中奪走。更糟的是,在單核心機器上忙碌等待可能是災難:自旋的執行緒霸佔了唯一的 CPU,於是它在等的那條執行緒根本沒機會執行去釋放鎖——一種自找的、像死結般的停滯。經驗法則是:只有在預期等待短於睡眠成本、而且持有者很可能正在另一顆核心上執行時,才忙碌等待;否則就用阻塞式(睡眠式)等待。真實系統常把兩者結合:先短暫自旋,若失敗再退回睡眠。

在單核心機器上,執行緒 A 在 while (locked) 裡自旋,等執行緒 B 釋放鎖。但 A 從不讓出 CPU,於是 B 永遠排不到執行去做釋放。系統就此卡死——忙碌等待餓死了它自己所依賴的那條執行緒。

自旋對極短的等待很快,對漫長的等待則浪費(甚至致命)。

忙碌等待並非總是壞事——對多核心上不到一微秒的等待,它可能勝過睡眠。危險在於為漫長的等待而自旋,或在單核心上為「不讓出就拿不到」的鎖自旋。

又稱
spinningpolling loopspin-wait忙等自旋等待