概念
Semaphore分為單值和多值兩種,前者只能被一個執行緒獲得,後者可以被若干個執行緒獲得。
以一個停車場是運作為例。為了簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛不受阻礙的進入,然後放下車攔,剩下的車則必須在入口等待,此後來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知後,打開車攔,放入一輛,如果又離開兩輛,則又可以放入兩輛,如此往復。
在這個停車場系統中,車位是公共資源,每輛車好比一個執行緒,看門人起的就是信號量的作用。
更進一步,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的執行緒(車輛)都會將該整數減一(通過它當然是為了使用資源),當該整數值為零時,所有試圖通過它的執行緒都將處於等待狀態。在信號量上我們定義兩種操作: Wait(等待) 和 Release(釋放)。 當一個執行緒調用Wait(等待)操作時,它要么通過然後將信號量減一,要么一直等下去,直到信號量大於一或逾時。Release(釋放)實際上是在信號量上執行加操作,對應於車輛離開停車場,該操作之所以叫做“釋放”是因為加操作實際上是釋放了由信號量守護的資源。
在java中,還可以設定該信號量是否採用公平模式,如果以公平方式執行,則執行緒將會按到達的順序(FIFO)執行,如果是非公平,則可以後請求的有可能排在佇列的頭部。
JDK中定義如下:
Semaphore(int permits, boolean fair) 創建具有給定的許可數和給定的公平設定的Semaphore。
信號標
信號量(英語:Semaphore)又稱為 信號量、 旗語,是一個同步對象,用於保持在0至指定最大值之間的一個計數值。當執行緒完成一次對該semaphore對象的等待(wait)時,該計數值減一;當執行緒完成一次對semaphore對象的釋放(release)時,計數值加一。當計數值為0,則執行緒等待該semaphore對象不再能成功直至該semaphore對象變成signaled狀態。semaphore對象的計數值大於0,為signaled狀態;計數值等於0,為nonsignaled狀態.
semaphore對象適用於控制一個僅支持有限個用戶的共享資源,是一種不需要使用忙碌等待(busy waiting)的方法。
信號量的概念是由荷蘭計算機科學家艾茲赫爾·戴克斯特拉(Edsger W. Dijkstra)發明的,廣泛的套用於不同的作業系統中。在系統中,給予每一個進程一個信號量,代表每個進程目前的狀態,未得到控制權的進程會在特定地方被強迫停下來,等待可以繼續進行的信號到來。如果信號量是一個任意的整數,通常被稱為計數信號量(Counting semaphore),或一般信號量(general semaphore);如果信號量只有二進制的0或1,稱為二進制信號量(binary semaphore)。在linux系統中,二進制信號量(binary semaphore)又稱互斥鎖(Mutex)。
語法
計數信號量具備兩種操作動作,之前稱為 V(又稱signal())與 P(wait())。 V操作會增加信號量 S的數值,P操作會減少它。
運作方式:
初始化,給與它一個非負數的整數值。
運行 P(wait()),信號量S的值將被減少。企圖進入臨界區塊的進程,需要先運行 P(wait())。當信號量S減為負值時,進程會被擋住,不能繼續;當信號量S不為負值時,進程可以獲準進入臨界區塊。
運行 V(又稱signal()),信號量S的值會被增加。結束離開臨界區塊的進程,將會運行 V(又稱signal())。當信號量S不為負值時,先前被擋住的其他進程,將可獲準進入臨界區塊。
1.初始化,給與它一個非負數的整數值。
2.運行 P(wait()),信號量S的值將被減少。企圖進入臨界區塊的進程,需要先運行 P(wait())。當信號量S減為負值時,進程會被擋住,不能繼續;當信號量S不為負值時,進程可以獲準進入臨界區塊。
3.運行 V(又稱signal()),信號量S的值會被增加。結束離開臨界區塊的進程,將會運行 V(又稱signal())。當信號量S不為負值時,先前被擋住的其他進程,將可獲準進入臨界區塊。
Windows API提供的semaphore
執行緒使用CreateSemaphore或CreateSemaphoreEx函式創建一個semaphore對象。此時可以指定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對象的執行緒會永久阻塞或逾時返回 。