共用方式為


同步處理基本概觀

.NET 提供一系列類型,可讓您用來同步存取共用資源或座標線程互動。

這很重要

使用相同的同步處理基本實例來保護共用資源的存取。 如果您使用不同的同步處理基本實例來保護相同的資源,您將規避同步處理基本類型所提供的保護。

WaitHandle 類別和輕量型同步處理類型

多個 .NET 同步處理基本類型衍生自 System.Threading.WaitHandle 類別,其封裝原生作系統同步處理句柄,並使用訊號機制進行線程互動。 這些類別包括:

在 .NET Framework 中,由於 WaitHandle 衍生自 System.MarshalByRefObject,因此這些類型可用來跨應用程式域界限同步處理線程的活動。

在 .NET Framework、.NET Core 和 .NET 5+中,其中一些類型可以代表具名的系統同步處理句柄,這些句柄在作系統中可見,而且可用於進程間同步處理:

如需詳細資訊,請參閱 WaitHandle API 參考。

輕量型同步處理類型不依賴基礎作系統句柄,而且通常會提供更好的效能。 不過,它們無法用於進程間同步處理。 在一個應用程式內,使用這些類型進行線程同步處理。

其中有些型別是衍生自 WaitHandle的型別替代方案。 例如, SemaphoreSlim 是的輕量型替代方案 Semaphore

共用資源存取的同步

.NET 提供一系列同步處理基本類型,以控制多個線程對共用資源的存取。

監視類別

類別 System.Threading.Monitor 透過在識別資源的物件上取得或釋放鎖定,提供對共用資源的互斥存取權。 當持有鎖時,持有鎖的線程可以再次取得並釋放鎖。 任何其他線程都遭到封鎖而無法取得鎖定,而且 Monitor.Enter 方法會等到鎖定釋放為止。 方法 Enter 會取得釋放的鎖定。 您也可以使用 Monitor.TryEnter 方法來指定線程嘗試取得鎖定的時間量。 因為類別 Monitor 具有線程親和性,因此取得鎖定的線程必須藉由呼叫 Monitor.Exit 方法來釋放鎖定。

您可以使用 Monitor.WaitMonitor.PulseMonitor.PulseAll 方法來協調執行緒的互動,以獲取同一物件上的鎖定。

如需詳細資訊,請參閱 Monitor API 參考。

備註

使用 C# 中的 lock 語句和 Visual Basic 中的 SyncLock 語句來同步存取共享資源,而不是直接使用 Monitor 類別。 這些語句是透過使用 EnterExit 方法以及 try…finally 程式區塊來實作,以確保取得的鎖定總是會被釋放。

Mutex 類別

類別 System.Threading.Mutex ,例如 Monitor,授與共用資源的獨佔存取權。 使用 Mutex.WaitOne 方法的其中一種多載,以請求 Mutex 的所有權。 如同 MonitorMutex 具有線程親和性,而且取得 Mutex 的線程必須藉由呼叫 Mutex.ReleaseMutex 方法來釋放它。

不同於 Monitor,類別 Mutex 可用於進程間同步處理。 若要這樣做,請使用可在整個操作系統中看到的具名互斥鎖(mutex)。 若要建立具名 Mutex 實例,請使用指定名稱的 Mutex 建構函式 。 您也可以呼叫 Mutex.OpenExisting 方法來開啟現有的具名系統 Mutex。

如需詳細資訊,請參閱 Mutexes 文章和 Mutex API 參考。

SpinLock 結構

結構 System.Threading.SpinLock ,例如 Monitor,會根據鎖定的可用性,授與共用資源的獨佔存取權。 嘗試取得SpinLock無法取得的鎖時,它會在迴圈中等候,重複檢查,直到鎖變成可用為止。

若需了解使用自旋鎖的優點和缺點的更多資訊,請參閱 SpinLock 文章和 SpinLock API 參考。

ReaderWriterLockSlim 類別

類別 System.Threading.ReaderWriterLockSlim 會授與共用資源的獨佔存取權以供寫入,並允許多個線程同時存取資源以供讀取。 您可能想要使用 ReaderWriterLockSlim 來同步存取支援安全線程讀取作業的共享數據結構,但需要獨佔存取才能執行寫入作業。 當執行緒要求獨佔存取權時(例如呼叫 ReaderWriterLockSlim.EnterWriteLock 方法),後續的讀取器和寫入器要求會被封鎖,直到所有現有的讀取器已退出鎖定,以及寫入器已進入並退出鎖定。

如需詳細資訊,請參閱 ReaderWriterLockSlim API 參考。

Semaphore 和 SemaphoreSlim 類別

System.Threading.SemaphoreSystem.Threading.SemaphoreSlim 類別會限制可以同時存取共用資源或資源集區的線程數目。 要求資源的其他執行緒會等到任何執行緒釋放信號量為止。 由於信號沒有線程親和性,線程可以取得信號,而另一個線程可以釋放它。

SemaphoreSlim 是的 Semaphore 輕量型替代方案,只能用於單一進程界限內的同步處理。

在 Windows 上,您可以用 Semaphore 來進行跨程序同步。 若要做到這一點,請使用指定名稱的其中一個Semaphore方法,建立代表具名系統訊號的Semaphore.OpenExisting實例。 SemaphoreSlim 不支援具名系統旗號。

如需詳細資訊,請參閱 Semaphore 和 SemaphoreSlim 文章和 SemaphoreSemaphoreSlim API 參考。

線程互動或訊號

線程互動(或線程訊號)表示線程必須等候一或多個線程的通知或訊號,才能繼續。 例如,如果線程 A 呼叫 Thread.Join 線程 B 的 方法,線程 A 就會遭到封鎖,直到線程 B 完成為止。 上一節所述的同步處理基本類型提供不同的訊號機制:藉由釋放鎖定,線程會通知另一個線程,藉由取得鎖定來繼續。

本節說明 .NET 所提供的其他訊號建構。

EventWaitHandle、AutoResetEvent、ManualResetEvent 和 ManualResetEventSlim 類別

類別 System.Threading.EventWaitHandle 代表線程同步處理事件。

同步事件可以處於未發出或已發出訊號的狀態。 當事件的狀態為未通知時,呼叫事件的 WaitOne 多載的線程會被封鎖,直到事件被通知為止。 方法會將 EventWaitHandle.Set 事件的狀態設定為已發出訊號。

已發出訊號的 EventWaitHandle 行為取決於其重設模式:

在 Windows 上,您可以用 EventWaitHandle 來進行跨程序同步。 若要這樣做,請使用其中一個指定名稱或EventWaitHandle方法的 EventWaitHandle 建構函式,建立EventWaitHandle.OpenExisting代表具名系統同步處理事件的實例。

如需詳細資訊,請參閱 EventWaitHandle 文章。 如需 API 參考,請參閱EventWaitHandleAutoResetEventManualResetEventManualResetEventSlim

CountdownEvent 類別

類別 System.Threading.CountdownEvent 表示當事件計數為零時,就會設定該事件。 雖然 CountdownEvent.CurrentCount 大於零,但會封鎖呼叫 CountdownEvent.Wait 的線程。 呼叫 CountdownEvent.Signal 以遞減事件的計數。

相較於 ManualResetEventManualResetEventSlim,可以用來使用一個線程的訊號解除多個線程的封鎖,您可以使用 CountdownEvent 來使用多個線程的訊號解除一或多個線程的封鎖。

如需詳細資訊,請參閱 CountdownEvent 文章和 CountdownEvent API 參考。

屏障類別

類別 System.Threading.Barrier 代表線程執行屏障。 呼叫Barrier.SignalAndWait 方法的線程會發出已到達屏障的訊號,並等到其他參與線程也到達屏障為止。 當所有參與線程都到達屏障時,它們會繼續進行,屏障會重設,並且可以再次使用。

在某些線程在繼續進行到下一個計算階段之前需要其他線程的結果時,您可以使用 Barrier

如需詳細資訊,請參閱 屏障 文章和 Barrier API 參考。

互鎖 (Interlocked) 類別

類別 System.Threading.Interlocked 提供靜態方法,能對變數執行簡單的原子操作。 這些原子操作包括加法、遞增和遞減、交換和依賴比較的條件交換,以及 64 位整數值的讀取操作。

如需詳細資訊,請參閱 Interlocked API 參考。

SpinWait 結構

結構 System.Threading.SpinWait 提供支援旋轉等待的功能。 當線程必須等待事件發出訊號或符合條件時,您可能會想要使用它,而當實際等待時間預期小於使用等候句柄機制或其他方式封鎖線程所需的等待時間時。 藉由使用 SpinWait,您可以指定一個在等候時忙碌等待的短時間,然後只有在指定時間內條件不滿足時,才會讓出控制權(例如,進入等候狀態或休眠)。

如需詳細資訊,請參閱 SpinWait 文章和 SpinWait API 參考。

另請參閱