Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

Threads และ Thread Synchronization ใน C#

ภาพรวม

Thread Synchronization ป้องกัน Race Condition เมื่อหลายเธรดเข้าถึง Shared Resource เครื่องมือหลัก: lock, Mutex, Monitor, Semaphore, ReaderWriterLockSlim

1. lock Statement (Monitor) - พื้นฐานที่สุด


public class BankAccount {
    private readonly object _lock = new object();
    private decimal _balance = 0;

    public void Deposit(decimal amount) {
        lock (_lock) {
            _balance += amount;
        }
    }

    public void Withdraw(decimal amount) {
        lock (_lock) {
            if (_balance >= amount) _balance -= amount;
        }
    }

    public decimal Balance {
        get {
            lock (_lock) return _balance;
        }
    }
}

2. Mutex - Cross-Process Synchronization


using System;
using System.Threading;

public class SingleInstanceApp {
    private static Mutex _mutex;

    public static void Main() {
        bool createdNew;
        _mutex = new Mutex(true, "Global\\MyUniqueAppName", out createdNew);

        if (!createdNew) {
            Console.WriteLine("Application already running.");
            return;
        }

        try {
            Console.WriteLine("Running... Press Enter to exit.");
            Console.ReadLine();
        }
        finally {
            _mutex.ReleaseMutex();
        }
    }
}

3. ThreadPool - จัดการ Thread ให้อัตโนมัติ


using System;
using System.Threading;

public class ThreadPoolDemo {
    public static void Main() {
        Console.WriteLine("Queueing work items...");

        for (int i = 0; i < 5; i++) {
            int taskNum = i;
            ThreadPool.QueueUserWorkItem(DoWork, taskNum);
        }

        Console.WriteLine("Main thread sleeping...");
        Thread.Sleep(2000);
        Console.WriteLine("Done.");
    }

    static void DoWork(object state) {
        int taskNum = (int)state;
        Console.WriteLine($"Task {taskNum} started on thread {Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(500);
        Console.WriteLine($"Task {taskNum} completed");
    }
}

4. ReaderWriterLockSlim - หลาย Reader, หนึ่ง Writer


using System;
using System.Threading;

public class SharedCache {
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    private readonly Dictionary<string, string> _cache = new Dictionary<string, string>();

    public string Get(string key) {
        _lock.EnterReadLock();
        try {
            return _cache.TryGetValue(key, out var value) ? value : null;
        }
        finally {
            _lock.ExitReadLock();
        }
    }

    public void Set(string key, string value) {
        _lock.EnterWriteLock();
        try {
            _cache[key] = value;
        }
        finally {
            _lock.ExitWriteLock();
        }
    }
}

5. SemaphoreSlim - จำกัดจำนวน Concurrent Access


using System;
using System.Threading;
using System.Threading.Tasks;

public class RateLimiter {
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Max 3 concurrent

    public async Task AccessResourceAsync() {
        await _semaphore.WaitAsync();
        try {
            Console.WriteLine($"Access granted. Thread: {Thread.CurrentThread.ManagedThreadId}");
            await Task.Delay(1000); // Simulate work
        }
        finally {
            _semaphore.Release();
        }
    }
}

เปรียบเทียบ Synchronization Primitives

PrimitiveUse CaseCross-ProcessPerformance
lock (Monitor)General purpose, short critical sectionsNoFast
MutexCross-process, single instance appYesSlower
ReaderWriterLockSlimRead-heavy workloadsNoGood for reads
SemaphoreSlimLimit concurrent access (throttling)NoGood
InterlockedAtomic operations on primitivesNoFastest
Concurrent CollectionsThread-safe data structuresNoBest for collections

Best Practices

  • Lock object ต้องเป็น private readonly object
  • Critical section ควรสั้นที่สุด (ไม่ควร I/O, Network calls ภายใน lock)
  • หลีกเลี่ยง Nested Locks (Deadlock risk)
  • ใช้ try/finally หรือ lock statement เพื่อให้ปล่อย lock แน่ใจ
  • พิจารณา Concurrent Collections ก่อนเขียน Lock เอง