Semaphore 和 SemaphoreSlim

System.Threading.Semaphore 類別代表具名 (系統) 或區域號誌。 它是 Win32 號誌物件周圍的精簡型包裝函式。 Win32 號誌是計算的號誌,可以用來控制資源集區的存取。

SemaphoreSlim 類別表示輕量型、快速的號誌,可以用於在預期等候時間較短的單一處理序內進行等候。 SemaphoreSlim 會盡可能依賴通用語言執行階段 (CLR) 所提供的同步處理原始物件。 不過,它也提供延遲初始化、核心架構的等候控制代碼,視需要支援等待多個號誌。 SemaphoreSlim 也支援使用取消語彙基元,但它不支援具名號誌或使用等候控制代碼進行同步處理。

管理有限的資源

執行緒進入旗號的方法是呼叫 WaitOne 方法,它是繼承自 WaitHandle 類別 (如果是 System.Threading.Semaphore 物件),或是 SemaphoreSlim.WaitSemaphoreSlim.WaitAsync 方法 (如果是 SemaphoreSlim 物件)。 當呼叫傳回時,號誌計數會遞減。 當執行緒要求進入,而計數為零時,則執行緒會封鎖。 當執行緒藉由呼叫 Semaphore.ReleaseSemaphoreSlim.Release 方法釋放號誌時,會允許封鎖的執行緒進入。 封鎖的執行緒進入號誌時沒有任何保證的順序,例如先進先出 (FIFO) 或後進先出 (LIFO)。

執行緒可以藉由重複呼叫 System.Threading.Semaphore 物件的 WaitOne 方法或 SemaphoreSlim 物件的 Wait 方法,來多次輸入旗號。 若要釋放號誌,執行緒可以呼叫 Semaphore.Release()SemaphoreSlim.Release() 方法多載相同的次數,或呼叫 Semaphore.Release(Int32)SemaphoreSlim.Release(Int32) 方法多載,並指定要釋放的項目數。

號誌和執行緒識別

兩種號誌類型不會在 WaitOneWaitReleaseSemaphoreSlim.Release 方法的呼叫上強制執行執行緒識別。 例如,一個號誌的常見使用案例,其涉及一個產生者執行緒和一個消費者執行緒,之中一個執行緒始終都會遞增號誌計數,另一個則始終遞減它。

程式設計人員要負責確保執行緒不會釋放號誌太多次。 例如,假設某個號誌的最大計數為 2,且執行緒 A 和執行緒 B 都進入號誌。 若執行緒 B 中的程式設計錯誤導致呼叫 Release 兩次,則兩次呼叫都會成功。 此時號誌計數已滿,當執行緒 A 終於呼叫 Release 時,就會擲回 SemaphoreFullException

具名號誌

Windows 作業系統允許有名稱的號誌。 具名號誌是全系統性的。 也就是說,一旦建立具名號誌,所有處理序中的所有執行緒都可看到它。 因此,具名號誌可以用來同步處理序及執行緒的活動。

您可以建立 Semaphore 物件,使用其中一個指定名稱的建構函式來代表具名系統號誌。

注意

由於具名號誌是全系統性的,因此可能有多個 Semaphore 物件,代表相同的具名號誌。 每次呼叫建構函式或 Semaphore.OpenExisting 方法時,便會建立新的 Semaphore 物件。 重複指定相同的名稱,會建立多個代表相同具名號誌的物件。

使用具名號誌時請小心。 因為它們是全系統性的,使用相同名稱的另一個處理序可能會意外地進入您的號誌。 在同一部電腦上執行的惡意程式碼便可使用此點作為拒絕服務攻擊的基礎。

使用存取控制安全性來保護代表具名號誌的 Semaphore 物件,最好是使用指定 System.Security.AccessControl.SemaphoreSecurity 物件的建構函式。 您也可以使用 Semaphore.SetAccessControl 方法套用存取控制安全性,但這會在建立號誌的時間與它受保護的時間之間留下弱點時段。 使用存取控制安全性來保護號誌,有助於防止惡意攻擊,但不能解決意外名稱衝突的問題。

另請參閱