ทั้ง Monitor และ lock จัดเตรียม Mechanism สำหรับ Synchronize Access ไปยัง Objects lock เป็น Shortcut สำหรับ Monitor.Enter พร้อม try และ finally
lock เป็น Shortcut และเป็น Option สำหรับ Basic Usage ถ้าต้องการ Control มากขึ้นสำหรับ Advanced Multithreading Solutions ใช้ TryEnter(), Wait(), Pulse(), PulseAll() Methods แล้ว Montior Class คือ Option ของคุณ
ตัวอย่าง Lock
class Program {
static object _lock = new object();
static int Total;
public static void Main() {
AddOneHundredLock();
Console.ReadLine();
}
public static void AddOneHundredLock() {
for (int i = 1; i <= 100; i++) {
lock (_lock) {
Total++;
}
}
}
}
ตัวอย่าง Monitor
class Program {
static object _lock = new object();
static int Total;
public static void Main() {
AddOneHundredMonitor();
Console.ReadLine();
}
public static void AddOneHundredMonitor() {
for (int i = 1; i <= 100; i++) {
Monitor.Enter(_lock);
try {
Total++;
}
finally {
Monitor.Exit(_lock);
}
}
}
}
Monitor Advanced Methods
TryEnter - Non-blocking Lock Attempt
public bool TryUpdateWithTimeout(int timeoutMs) {
// ลอง Lock ภายใน Timeout ไม่ Block แบบนิรันดร์
if (Monitor.TryEnter(_lock, timeoutMs)) {
try {
// Critical Section
return true;
}
finally {
Monitor.Exit(_lock);
}
}
return false; // Lock ไม่ได้ภายใน Timeout
}
Wait/Pulse - Thread Signaling
class BoundedBuffer {
private readonly Queue _queue = new Queue();
private readonly int _capacity;
private readonly object _lock = new object();
public void Produce(T item) {
lock (_lock) {
while (_queue.Count >= _capacity) {
Monitor.Wait(_lock); // Release Lock และ Wait
}
_queue.Enqueue(item);
Monitor.Pulse(_lock); // Notify One Waiting Consumer
}
}
public T Consume() {
lock (_lock) {
while (_queue.Count == 0) {
Monitor.Wait(_lock); // Release Lock และ Wait
}
var item = _queue.Dequeue();
Monitor.Pulse(_lock); // Notify One Waiting Producer
return item;
}
}
}
PulseAll - Notify All Waiting Threads
// ใช้เมื่อ State Change อาจส่งผลต่อ Multiple Waiting Threads
Monitor.PulseAll(_lock);
เปรียบเทียบ Lock vs Monitor
| Feature | lock | Monitor |
|---|---|---|
| Syntax | Simple (Syntactic Sugar) | Verbose (Explicit Enter/Exit) |
| Exception Safety | Auto (try/finally Generated) | Manual (ต้องเขียน try/finally เอง) |
| TryEnter (Timeout) | ไม่ได้ | ได้ |
| Wait/Pulse/PulseAll | ไม่ได้ | ได้ |
| Readability | สูง | ต่ำกว่า |
| Performance | เหมือนกัน (Compile to Monitor) | Baseline |
lock Compiles To
// Source
lock (obj) {
DoWork();
}
// Compiled (Conceptually)
var temp = obj;
Monitor.Enter(temp);
try {
DoWork();
}
finally {
Monitor.Exit(temp);
}
Best Practices
- ใช้ lock สำหรับ Simple Mutual Exclusion (90%+ ของ Cases)
- ใช้ Monitor.TryEnter เมื่อต้องการ Timeout หรือ Non-blocking
- ใช้ Monitor.Wait/Pulse สำหรับ Producer-Consumer Patterns
- Lock Object ควรเป็น
private readonly objectเฉพาะสำหรับ Locking - หลีกเลี่ยง lock บน
this,typeof(Type), String Literals - Critical Section ควรสั้นที่สุดเท่าที่จะเป็นไปได้
ใน .NET Modern: 他の選択肢
SemaphoreSlim- Async-friendly, LightweightReaderWriterLockSlim- Multiple Readers, Single WriterInterlocked- Atomic Operations (Counters, Flags)Concurrent Collections- Thread-safe Collections (Dictionary, Queue, Bag)Channels- Producer-Consumer (System.Threading.Channels)