號誌 (程式設計)
信號量(英語: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操作會減少它。
運作方式:
- 初始化,給與它一個非負數的整數值。
- 執行P(
wait()
),信號標S的值將被減少。企圖進入臨界區段的行程,需要先執行P(wait()
)。當信號標S減為負值時,行程會被擋住,不能繼續;當信號標S不為負值時,行程可以獲准進入臨界區段。 - 執行V(
signal()
),信號標S的值會被增加。結束離開臨界區段的行程,將會執行V(signal()
)。當信號標S不為負值時,先前被擋住的其他行程,將可獲准進入臨界區段。
Windows API提供的semaphore
線程使用CreateSemaphore或CreateSemaphoreEx函數創建一個semaphore對象[2]。此時可以指定semaphore的當前計數值與計數值上限;也可指定semaphore對象的名字。其他進程中的線程可以指出已存在的semaphore對象的名字通過調用OpenSemaphore函數打開它。
如果多個線程在等待一個semaphore對象,不保證按照先進先出(FIFO)順序調度這些等待線程。外部事件,如內核模式的異步過程調用可改變等待順序。
在semaphore對象為signaled狀態時,等待函數返回會把該semaphore對象計數值減1。函數ReleaseSemaphore把semaphore對象的計數值增加指定的值。任何線程,哪怕它沒有等待完成過該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對象的線程會永久阻塞或超時返回。
參見
參考資料
- ^ 戴克斯特拉, 艾茲赫爾. Over de sequentialiteit van procesbeschrijvingen (EWD-74) (PDF). E·W·戴克斯特拉檔案館. 得克薩斯大學奧斯汀分校美國歷史中心. (文字版本)
- ^ MSDN:Semaphore Objects. [2016-09-05]. (原始內容存檔於2016-09-16).
外部連結
- semaphore.h(頁面存檔備份,存於網際網路檔案館) programming interface - The Open Group Base Specifications Issue 6, IEEE Std 1003.1
- The Little Book of Semaphores(頁面存檔備份,存於網際網路檔案館) Allen B. Downey
- A pragmatic, historically oriented survey on the universality of synchronization primitives (頁面存檔備份,存於網際網路檔案館), Jouni Leppäjärvi