Monitor 是 .NET 提供的同步基礎設施,lock 關鍵字編譯後即為 Monitor.Enter/Exit。Monitor 提供更精細的控制:
| 方法 | 說明 |
|---|---|
Enter(object) | 取得物件鎖,阻塞至成功 |
TryEnter(object) | 嘗試取得鎖,立即返回 bool |
TryEnter(object, TimeSpan) | 帶超時嘗試取得鎖 |
Exit(object) | 釋放鎖 |
Wait(object) | 釋放鎖並進入等待隊列 |
Wait(object, TimeSpan) | 帶超時等待 |
Pulse(object) | 喚醒一個等待線程 |
PulseAll(object) | 喚醒所有等待線程 |
object syncObj = new object();
Monitor.Enter(syncObj);
try
{
// 臨界區
}
finally
{
Monitor.Exit(syncObj);
}
// 等同於:
lock (syncObj) { /* 臨界區 */ }
if (Monitor.TryEnter(syncObj, TimeSpan.FromSeconds(2)))
{
try { /* 臨界區 */ }
finally { Monitor.Exit(syncObj); }
}
else
{
Console.WriteLine("取得鎖超時,放棄操作");
}
using System;
using System.Collections.Generic;
using System.Threading;
public class BoundedBuffer<T>
{
private readonly Queue<T> queue = new Queue<T>();
private readonly int capacity;
private readonly object sync = new object();
public BoundedBuffer(int capacity) { this.capacity = capacity; }
public void Produce(T item)
{
lock (sync)
{
while (queue.Count == capacity)
Monitor.Wait(sync); // 滿了等待
queue.Enqueue(item);
Monitor.Pulse(sync); // 通知消費者
}
}
public T Consume()
{
lock (sync)
{
while (queue.Count == 0)
Monitor.Wait(sync); // 空了等待
T item = queue.Dequeue();
Monitor.Pulse(sync); // 通知生產者
return item;
}
}
}
// 使用範例
class Program
{
static BoundedBuffer<int> buffer = new BoundedBuffer<int>(5);
static void Main()
{
new Thread(Producer).Start();
new Thread(Consumer).Start();
Thread.Sleep(5000);
}
static void Producer()
{
for (int i = 0; i < 20; i++)
{
buffer.Produce(i);
Console.WriteLine("生產: {0}", i);
Thread.Sleep(100);
}
}
static void Consumer()
{
for (int i = 0; i < 20; i++)
{
int item = buffer.Consume();
Console.WriteLine("消費: {0}", item);
Thread.Sleep(150);
}
}
}
關鍵:Wait 必須在 lock/Enter 保護下呼叫,否則拋出 SynchronizationLockException。
| 場景 | 建議 |
|---|---|
| 簡單互斥 | lock(語法簡潔、自動 finally) |
| 需嘗試取得鎖/超時 | Monitor.TryEnter |
| 條件同步/生產者消費者 | Monitor.Wait/Pulse |
| 需在不同方法間釋放/取得鎖 | Monitor.Enter/Exit 手動控制 |
(原文包含六張圖片,展示 Monitor 方法結構、Wait/Pulse 狀態轉換、生產者消費者時序圖、鎖升級等)