前面利用 Lock
這種互斥鎖,來達到共用資源的同步。接下來,來討論非排他鎖(nonexclusive locking) 的同步機制 Semaphore。
回到慣例,在開始之前,還是先來看個現實的例子。
有一個位於辦公大樓旁的平面停車場,該停車場擁有五十個車位。
一到上班時間,車輛就會開始湧入停車場。車輛進場時,管理員會給車輛一張停車證。離場時,依停車證繳費離場。
一但車位己滿,停車場的管理員禁止其他車輛入場。讓它們在門口等待。直到有車輛離場,空出車位後,才會再次放行。
從上面的例子中,可以觀察到幾個重點,這幾點正好可以說明 semaphore 的概念。
再看 Wiki 是如何解釋 Semaphoreh 的。
號誌(semaphore)又稱為旗號,是一個同步物件,用於保持在0至指定最大值之間的一個計數值。
當執行緒完成一次對 semaphore 物件的等待( wait )時,該計數值減一;
當執行緒完成一次對 semaphore 物件的釋放( release ) 時,計數值加一。當計數值為0,則執行緒等待該 semaphore 物件不再能成功,直至該 semaphore 物件變成 signaled 狀態。
semaphore物件的計數值大於0,為 signaled 狀態;計數值等於0,為 nonsignaled 狀態
將 Wiki 上的說明,與上面實例相互對照,會比較清楚。
依筆者的理解,Samaphore 本身的設計方向,就是管理執行緒的對資源的操作,它運用信號的概念,管理多個執行緒,判定何時可以對資源進行操作,卻無法保證進入的順序,例如 FIFO 或 LIFO。
那為什麼網路查詢生產者與消費者模式時,都會提到 Samaphore 呢?
還記得 semaphore 必須指定最大值的條件嗎?
當 semaphore 的最大值設為一時,可視為同一個時間內,只有一個執行緒才能存取資源。變向的達到互斥鎖的功用。
因此,當 semaphore 的值為任意正整數時, 被稱為計數號誌(Counting semaphore);若semaphore 的值為二進位的 0 或 1 ,則稱為二進位號誌(binary semaphore)。
要特別注意的是,雖然二進位號誌與**互斥鎖(Mutex)**,兩者的邏輯與行為十分相似,但還是必須確實區分兩者間的差異。
如果想要進一步了解,可以參考 概念性、宏觀視野的程序/執行緒同步機制總覽 這篇文章。
在 .Net 之中,提供了 Semaphore
與 Mutex
兩類型,但是筆者自己來不及實作,所以沒有實作。若有興趣,可以直接查看 MSDN 的 Semaphore Class、Mutex Class。