在多線程程式設計中,資源同步是核心課題。.NET 提供了豐富的同步工具箱,針對不同場景選擇適當機制,才能兼顧效能與正確性。本文系統整理七種常見同步方式,並附上實戰程式碼。
將欄位標記為 volatile,告訴編譯器與 CLR 不要對該欄位進行優化重排,確保每次讀取都能拿到最新值。適用類型包括:參考型別、指標(unsafe)、基本數值型別(sbyte, byte, short, ushort, int, uint, char, float, bool)以及以這些為基礎的列舉型別。
看似簡單的 i = i + 1 實際包含讀取、加一、寫回三步驟,多線程下極易產生競態條件。System.Threading.Interlocked 提供原子操作方法:
Increment(ref int):原子遞增Decrement(ref int):原子遞減Exchange(ref int, int):原子交換數值int i = 0;
Interlocked.Increment(ref i); // i = 1
Interlocked.Decrement(ref i); // i = 0
Interlocked.Exchange(ref i, 100); // i = 100
lock(obj) { ... } 相當於 Monitor.Enter/Exit 的語法糖,確保同一時間只有一個線程進入關鍵區段。簡單易用,但缺乏嘗試鎖定、超時等進階控制。
提供 TryEnter(嘗試獲取鎖,失敗立即返回)、Wait/Pulse/PulseAll(等待/喚醒機制),支援「生產者-消費者」等複雜協作模式。範例展示如何用 Wait/Pulse 實現座位等待通知:
lock (m_isFull) {
Console.WriteLine("Wait for seat");
Monitor.Wait(m_isFull); // 釋放鎖並阻塞
Console.WriteLine("Have a good lunch!");
}
// 另一線程
lock (m_isFull) {
Console.WriteLine("Seat changed");
Monitor.Pulse(m_isFull); // 唤醒等待線程
}
功能類似 Monitor,但 Mutex 是系統級核心物件,可跨進程甚至跨機器同步。適用於多個獨立程式存取共享資源(如設定檔)的場景。透過 WaitOne() 獲取、ReleaseMutex() 釋放。
當「讀多寫少」時,獨佔鎖會嚴重降低並發度。ReaderWriterLock 允許多個線程同時讀取,但寫入時需獨佔,且寫入期間阻塞所有讀取。適合快取、設定資料等場景。
標記類別為 [Synchronization] 並繼承 ContextBoundObject,CLR 會自動為該類別實例加上同步域,確保同一時間只有一個線程能執行其方法。屬於「上下文繫結」進階技術,使用需謹慎評估效能影響。
AutoResetEvent、ManualResetEvent、Semaphore、EventWaitHandle 等基於事件訊號機制,適合線程間協作排程,詳細用法請參考 MSDN 文件。