Semaphore 和 SemaphoreSlimSemaphore and SemaphoreSlim

System.Threading.Semaphore 類別代表具名 (系統) 或區域號誌。The System.Threading.Semaphore class represents a named (systemwide) or local semaphore. 它是 Win32 號誌物件周圍的精簡型包裝函式。It is a thin wrapper around the Win32 semaphore object. Win32 號誌是計算的號誌,可以用來控制資源集區的存取。Win32 semaphores are counting semaphores, which can be used to control access to a pool of resources.

SemaphoreSlim 類別表示輕量型、快速的號誌,可以用於在預期等候時間較短的單一處理序內進行等候。The SemaphoreSlim class represents a lightweight, fast semaphore that can be used for waiting within a single process when wait times are expected to be very short. SemaphoreSlim 會盡可能依賴通用語言執行階段 (CLR) 所提供的同步處理原始物件。SemaphoreSlim relies as much as possible on synchronization primitives provided by the common language runtime (CLR). 不過,它也提供延遲初始化、核心架構的等候控制代碼,視需要支援等待多個號誌。However, it also provides lazily initialized, kernel-based wait handles as necessary to support waiting on multiple semaphores. SemaphoreSlim 也支援使用取消語彙基元,但它不支援具名號誌或使用等候控制代碼進行同步處理。SemaphoreSlim also supports the use of cancellation tokens, but it does not support named semaphores or the use of a wait handle for synchronization.

管理有限的資源Managing a Limited Resource

執行緒進入旗號的方法是呼叫 WaitOne 方法,它是繼承自 WaitHandle 類別 (如果是 System.Threading.Semaphore 物件),或是 SemaphoreSlim.WaitSemaphoreSlim.WaitAsync 方法 (如果是 SemaphoreSlim 物件)。Threads enter the semaphore by calling the WaitOne method, which is inherited from the WaitHandle class, in the case of a System.Threading.Semaphore object, or the SemaphoreSlim.Wait or SemaphoreSlim.WaitAsync method, in the case of a SemaphoreSlim object. 當呼叫傳回時,號誌計數會遞減。When the call returns, the count on the semaphore is decremented. 當執行緒要求進入,而計數為零時,則執行緒會封鎖。When a thread requests entry and the count is zero, the thread blocks. 當執行緒藉由呼叫 Semaphore.ReleaseSemaphoreSlim.Release 方法釋放號誌時,會允許封鎖的執行緒進入。As threads release the semaphore by calling the Semaphore.Release or SemaphoreSlim.Release method, blocked threads are allowed to enter. 封鎖的執行緒進入號誌時沒有任何保證的順序,例如先進先出 (FIFO) 或後進先出 (LIFO)。There is no guaranteed order, such as first-in, first-out (FIFO) or last-in, first-out (LIFO), for blocked threads to enter the semaphore.

執行緒可以重複呼叫 System.Threading.Semaphore 物件的 WaitOne 方法或 SemaphoreSlim 物件的 Wait 方法,多次進入號誌。A thread can enter the semaphore multiple times by calling the System.Threading.Semaphore object's WaitOne method or the SemaphoreSlim object's Wait method repeatedly. 若要釋放號誌,執行緒可以呼叫 Semaphore.Release()SemaphoreSlim.Release() 方法多載相同的次數,或呼叫 Semaphore.Release(Int32)SemaphoreSlim.Release(Int32) 方法多載,並指定要釋放的項目數。To release the semaphore, the thread can either call the Semaphore.Release() or SemaphoreSlim.Release() method overload the same number of times, or call the Semaphore.Release(Int32) or SemaphoreSlim.Release(Int32) method overload and specify the number of entries to be released.

號誌和執行緒識別Semaphores and Thread Identity

兩種號誌類型不會在 WaitOneWaitReleaseSemaphoreSlim.Release 方法的呼叫上強制執行執行緒識別。The two semaphore types do not enforce thread identity on calls to the WaitOne, Wait, Release, and SemaphoreSlim.Release methods. 例如,一個號誌的常見使用案例,其涉及一個產生者執行緒和一個消費者執行緒,之中一個執行緒始終都會遞增號誌計數,另一個則始終遞減它。For example, a common usage scenario for semaphores involves a producer thread and a consumer thread, with one thread always incrementing the semaphore count and the other always decrementing it.

程式設計人員要負責確保執行緒不會釋放號誌太多次。It is the programmer's responsibility to ensure that a thread does not release the semaphore too many times. 例如,假設某個號誌的最大計數為 2,且執行緒 A 和執行緒 B 都進入號誌。For example, suppose a semaphore has a maximum count of two, and that thread A and thread B both enter the semaphore. 如果執行緒 B 中的程式設計錯誤導致呼叫 Release 兩次,兩次呼叫都會成功。If a programming error in thread B causes it to call Release twice, both calls succeed. 此時號誌計數已滿,當執行緒 A 終於呼叫 Release 時,就會擲回 SemaphoreFullExceptionThe count on the semaphore is full, and when thread A eventually calls Release, a SemaphoreFullException is thrown.

具名號誌Named Semaphores

Windows 作業系統允許有名稱的號誌。The Windows operating system allows semaphores to have names. 具名號誌是全系統性的。A named semaphore is system wide. 也就是說,一旦建立具名號誌,所有處理序中的所有執行緒都可看到它。That is, once the named semaphore is created, it is visible to all threads in all processes. 因此,具名號誌可以用來同步處理序及執行緒的活動。Thus, named semaphore can be used to synchronize the activities of processes as well as threads.

您可以建立 Semaphore 物件,使用其中一個指定名稱的建構函式來代表具名系統號誌。You can create a Semaphore object that represents a named system semaphore by using one of the constructors that specifies a name.

注意

由於具名號誌是全系統性的,因此可能有多個 Semaphore 物件,代表相同的具名號誌。Because named semaphores are system wide, it is possible to have multiple Semaphore objects that represent the same named semaphore. 每次呼叫建構函式或 Semaphore.OpenExisting 方法時,便會建立新的 Semaphore 物件。Each time you call a constructor or the Semaphore.OpenExisting method, a new Semaphore object is created. 重複指定相同的名稱,會建立多個代表相同具名號誌的物件。Specifying the same name repeatedly creates multiple objects that represent the same named semaphore.

使用具名號誌時請小心。Be careful when you use named semaphores. 因為它們是全系統性的,使用相同名稱的另一個處理序可能會意外地進入您的號誌。Because they are system wide, another process that uses the same name can enter your semaphore unexpectedly. 在同一部電腦上執行的惡意程式碼便可使用此點作為拒絕服務攻擊的基礎。Malicious code executing on the same computer could use this as the basis of a denial-of-service attack.

使用存取控制安全性來保護代表具名號誌的 Semaphore 物件,最好是使用指定 System.Security.AccessControl.SemaphoreSecurity 物件的建構函式。Use access control security to protect a Semaphore object that represents a named semaphore, preferably by using a constructor that specifies a System.Security.AccessControl.SemaphoreSecurity object. 您也可以使用 Semaphore.SetAccessControl 方法套用存取控制安全性,但這會在建立號誌的時間與它受保護的時間之間留下弱點時段。You can also apply access control security using the Semaphore.SetAccessControl method, but this leaves a window of vulnerability between the time the semaphore is created and the time it is protected. 使用存取控制安全性來保護號誌,有助於防止惡意攻擊,但不能解決意外名稱衝突的問題。Protecting semaphores with access control security helps prevent malicious attacks, but does not solve the problem of unintentional name collisions.

另請參閱See also