行程同步與臨界區間問題

臨界區間(critical section)

想像整間辦公室共用一間小廁所。一次只能一個人用,所以門上有把鎖。廁所本身是危險的共用資源;而你「待在裡面」的那段時間,正是一天當中絕不能和別人重疊的部分。臨界區間就是這間廁所的軟體版本:它是程式中某一段特定的程式碼,執行緒在這段裡讀取並修改共用資料,因此若兩條執行緒同時跑這一段,就可能毀損那份資料。

具體來說,一條執行緒的程式碼通常在概念上分成四個部分:進入區(在此請求進入許可)、臨界區間(在此真正碰觸共用資料)、離開區(在此交出許可)、以及剩餘區(其餘所有部分,可以安全地並行執行)。整個同步的工藝,就是把進入區與離開區設計成:任何時刻都不會有兩條執行緒同時待在各自的臨界區間裡。臨界區間應盡可能短——只放真正會碰觸共用狀態的那幾行——因為當一條執行緒在裡面時,其他需要它的執行緒都得等待,過長的臨界區間會扼殺並行度。

一個常見的誤解是,把臨界區間當成「資料的性質」或「某個函式的性質」。它其實是「每一條會碰觸到該共用資料的程式路徑」的共同性質。只要有一條執行緒不經過進入區就讀寫了那個共用變數,整個保護就破功了——無論其他每條執行緒多麼小心,這一次的疏忽存取都可能毀掉一切。找出所有會碰觸某份共用狀態的臨界區間,是寫出正確並行程式的第一步,也是最容易出錯的一步。

在銀行裡,transfer(a, b, amt) 會讀取兩個餘額、從 a 扣款、再加到 b。這幾行就是臨界區間:若兩筆都碰到帳戶 a 的轉帳交錯執行,錢可能憑空產生或消失。填寫存提款單、寫狀態日誌、列印收據等,都屬於剩餘區,不需保護。

進入區 -> 臨界區間 -> 離開區 -> 剩餘區;臨界區間要保持極短。

臨界區間本身保護不了任何東西,除非每一條碰觸共用資料的路徑都遵守同一套進入/離開的紀律。別處只要有一次未同步的存取,就足以讓它全盤失效。

又称
critical region臨界區段臨界區域