訊號量(英語:semaphore)又稱為訊號標,是一個同步物件,用於保持在0至指定最大值之間的一個計數值。當執行緒完成一次對該semaphore物件的等待(wait)時,該計數值減一;當執行緒完成一次對semaphore物件的釋放(release)時,計數值加一。當計數值為0,則執行緒等待該semaphore物件不再能成功直至該semaphore物件變成signaled狀態。semaphore物件的計數值大於0,為signaled狀態;計數值等於0,為nonsignaled狀態。

訊號量的概念是由荷蘭電腦科學家艾茲赫爾·戴克斯特拉Edsger W. Dijkstra)發明的[1],廣泛的應用於不同的作業系統中。在系統中,給予每一個行程一個訊號量,代表每個行程目前的狀態,未得到控制權的行程會在特定地方被強迫停下來,等待可以繼續進行的訊號到來。如果訊號量是一個任意的整數,通常被稱為計數訊號量(Counting semaphore),或一般訊號量(general semaphore);如果訊號量只有二進位的0或1,稱為二進位訊號量(binary semaphore)。

語法

計數訊號量具備兩種操作動作,稱為V(signal())與P(wait())(即部分參考書常稱的「PV操作」)。V操作會增加訊號標S的數值,P操作會減少它。

運作方式:

  1. 初始化,給與它一個非負數的整數值。
  2. 執行P(wait()),訊號標S的值將被減少。企圖進入臨界區段的行程,需要先執行P(wait())。當訊號標S減為負值時,行程會被擋住,不能繼續;當訊號標S不為負值時,行程可以獲准進入臨界區段。
  3. 執行V(signal()),訊號標S的值會被增加。結束離開臨界區段的行程,將會執行V(signal())。當訊號標S不為負值時,先前被擋住的其他行程,將可獲准進入臨界區段

Windows API提供的semaphore

執行緒使用CreateSemaphoreCreateSemaphoreEx函數建立一個semaphore物件[2]。此時可以指定semaphore的當前計數值與計數值上限;也可指定semaphore物件的名字。其他行程中的執行緒可以指出已存在的semaphore物件的名字通過呼叫OpenSemaphore函數打開它。

如果多個執行緒在等待一個semaphore物件,不保證按照先進先出(FIFO)順序排程這些等待執行緒。外部事件,如內核模式的非同步過程呼叫可改變等待順序。

semaphore物件為signaled狀態時,等待函數返回會把該semaphore物件計數值減1。函數ReleaseSemaphoresemaphore物件的計數值增加指定的值。任何執行緒,哪怕它沒有等待完成過該semaphore物件,也可以使用ReleaseSemaphore來增加semaphore物件的計數。如果ReleaseSemaphore導致物件計數值超過上限,則該函數呼叫失敗,返回298號錯誤:「Too many posts were made to a semaphore」。

一個執行緒多次等待同一個semaphore物件,每次等待操作完成都會降低semaphore物件計數值(直至計數值為0時該執行緒阻塞)。然而,通過multiple-object等待函數使用一個陣列包含着同一個semaphore物件的多個控制代碼,不能實現對這個semaphore物件計數值的多次下降。

用完semaphore物件後,呼叫CloseHandle函數關閉它。semaphore物件的最後一個控制代碼被關閉後,作業系統會摧毀它。關閉semaphore並不影響它的計數值。因此,關閉semaphore前或者行程終止前,要確保已經正確呼叫過ReleaseSemaphore。否則,掛起等待該semaphore物件的執行緒會永久阻塞或逾時返回。

參見

參考資料

  1. ^ 戴克斯特拉, 艾茲赫爾. Over de sequentialiteit van procesbeschrijvingen (EWD-74) (PDF). E·W·戴克斯特拉檔案館. 德克薩斯大學奧斯汀分校美國歷史中心.  (文字版本)
  2. ^ MSDN:Semaphore Objects. [2016-09-05]. (原始內容存檔於2016-09-16). 

外部連結