存取共享資料時需顯式同步。.NET Framework 4 在 System.Threading 提供 6 個輕量級同步原語,避免昂貴鎖機制,適用於等待時間短的情境:
ManualResetEvent。Semaphore。範例:模擬 N 人各煮 3 次飯,步驟:打水→淘米→放鍋→蓋蓋→生火。每階段所有人完成才能進入下一階段。
private static Barrier _barrier = new Barrier(_participants, (b) =>
Console.WriteLine("當前階段:{0}", b.CurrentPhaseNumber));
// 工作方法中每步驟結束呼叫
_barrier.SignalAndWait();
結果:並發版本保證階段順序且大幅降低總耗時(圖表對比)。ContinueWhenAll 在所有任務完成後執行延續邏輯(統計耗時、釋放資源)。
if (!_barrier.SignalAndWait(2000)) // 等待 2 秒
throw new OperationCanceledException("等待超時");
try { _barrier.SignalAndWait(); }
catch (Exception ex) { /* 記錄異常 */ continue; }
任務完成後檢查 task.Exception 輸出異常報表。
Monitor.Enter/Exit 與 lock 等價,但 Monitor 提供 TryEnter(支援逾時)、Wait/Pulse/PulseAll 等進階控制。
適用於關鍵區極短、競爭不激烈情境。注意:不可宣告為 readonly 欄位,否則每次存取取得新副本導致鎖失效。
「輕量級 lock」:保證可見性(最新值可見),但不具原子性。適用於讀多寫少、簡單旗標同步,效能優於鎖且不阻塞。
ManualResetEventSlim mres = new ManualResetEventSlim(false);
Task observer = Task.Factory.StartNew(() => {
mres.Wait();
while (true) { if (mres.IsSet) { /* 執行工作 */ } Thread.Sleep(100); }
});
Thread.Sleep(2000);
mres.Set(); // 釋放等待
mres.Reset(); // 重置為無信號
mres.Set();
結合自旋與核心等待,短等待高效能。跨進程/AppDomain 需用 ManualResetEvent。
SemaphoreSlim ss = new SemaphoreSlim(3); // 最大並發 3 ss.Wait(); // 進入,計數 -1 ss.Release(); // 離開,計數 +1 ss.Release(3); // 一次釋放 3
計數信號量協調資源存取,不保證進入順序。短等待低開銷。
CountdownEvent cde = new CountdownEvent(3); // 初始計數 3 cde.Signal(); // 計數 -1 cde.Wait(); // 阻塞至計數歸零 cde.Reset(); // 重置為初始計數 cde.Reset(5); // 重置為指定計數 cde.AddCount(2); // 增加計數
適用於 Fork/Join 模式追蹤動態任務完成,開銷小於 Task.WaitAll。可重複重置實現多輪計數。
作者:釋迦苦僧|出處:https://www.cnblogs.com/woxpp