Location>code7788 >text

c# A way to control access to shared resources in a multithreaded environment

Popularity:705 ℃/2024-07-29 17:01:45
  1. Monitor:
    • Definition:Monitor is the most basic synchronization mechanism in C#, and is implemented via theEnter cap (a poem)Exit method to control access to shared resources. It provides exclusive locking to ensure that only one thread can access the shared resource at any given moment.
    • Advantages: easy to use, suitable for coarse-grained synchronization control of critical zones.
    • Disadvantages: can only realize the exclusion lock, can not realize the read-write lock, performance is relatively low.

class Program
{
    static readonly object _lock = new object();
    static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 10; i++)
        {
            new Thread(IncrementCounter).Start();
        }

        ();
    }

    static void IncrementCounter()
    {
        lock (_lock)
        {
            _counter++;
            ($"Counter: {_counter}");
        }
    }
}
View Code

 

  1. Mutex:
    • Definition:Mutex is an operating system object that is used to be shared between processes via theWaitOne respond in singingReleaseMutex to control access to shared resources. It provides the ability to synchronize between processes.
    • Pros: can be used across processes, suitable for synchronization between processes.
    • Cons: Compared toMonitor, the performance overhead is higher because of the system calls involved.

class Program
{
    static Mutex _mutex = new Mutex();
    static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 10; i++)
        {
            new Thread(IncrementCounter).Start();
        }

        ();
    }

    static void IncrementCounter()
    {
        _mutex.WaitOne();
        _counter++;
        ($"Counter: {_counter}");
        _mutex.ReleaseMutex();
    }
}
Mutex

 

  1. ReaderWriterLockSlim:
    • Definition:ReaderWriterLockSlim A read-write separation lock is implemented to allow multiple threads to read the shared resource at the same time, but only one thread is allowed to write to the shared resource. This mechanism is suitable for scenarios with many reads and few writes.
    • Pros: suitable for scenarios with many reads and few writes, improves concurrency performance.
    • Cons: relatively complex, may cause deadlocks, does not support recursive locks.

class Program
{
    static ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
    static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(ReadCounter).Start();
            new Thread(IncrementCounter).Start();
        }

        ();
    }

    static void ReadCounter()
    {
        _rwLock.EnterReadLock();
        ($"Counter: {_counter}");
        _rwLock.ExitReadLock();
    }

    static void IncrementCounter()
    {
        _rwLock.EnterWriteLock();
        _counter++;
        ($"Counter incremented to: {_counter}");
        _rwLock.ExitWriteLock();
    }
}
ReaderWriterLockSlim

 

  1. Semaphore:
    • Definition:Semaphore is a semaphore used to control the number of threads accessing a shared resource at the same time. The number of threads accessing a shared resource at the same time is controlled by theWaitOne cap (a poem)Release method, you can control the number of threads accessing the resource.
    • Pros: you can control the number of multiple threads accessing shared resources at the same time, higher flexibility.
    • Cons: More complex to use compared to other mechanisms, requires careful handling of semaphore releases.

class Program
{
    static Semaphore _semaphore = new Semaphore(2, 2); // Allow 2 threads to access the resource simultaneously
    static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(IncrementCounter).Start();
        }

        ();
    }

    static void IncrementCounter()
    {
        _semaphore.WaitOne();
        _counter++;
        ($"Counter: {_counter}");
        _semaphore.Release();
    }
}
Semaphore

 

  1. SemaphoreSlim:
    • Definition:SemaphoreSlim is a lightweight semaphore, similar to theSemaphore Similarly, it is used to control the number of threads accessing a shared resource at the same time, but compared to theSemaphore Lighter.
    • Pros: Compared toSemaphoreSemaphoreSlim has less overhead and is suitable for scenarios with frequent resource access.
    • Disadvantages: withSemaphore Compared to this, the functionality is slightly limited, e.g. there is noRelease(Int32) method, which can only increment the semaphore by one unit.
class Program
{
    static SemaphoreSlim _semaphore = new SemaphoreSlim(2, 2); // Allow 2 threads to access the resource simultaneously
    static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(IncrementCounter).Start();
        }

        ();
    }

    static void IncrementCounter()
    {
        _semaphore.Wait();
        _counter++;
        ($"Counter: {_counter}");
        _semaphore.Release();
    }
}
SemaphoreSlim

 

  1. lock:
    • Definition:lock is a keyword in C# used to implement mutex locks at the block level to protect shared resources from being accessed by multiple threads at the same time.
    • Advantages: easy to use, suitable for fine-grained synchronization control of critical zones, easier to write.
    • Disadvantages: can only be used for synchronization within a single thread, not across threads or processes, and can lead to deadlocks if not used carefully.
class Program
{
    static readonly object _lock = new object();
    static int _counter = 0;

    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(IncrementCounter).Start();
        }

        ();
    }

    static void IncrementCounter()
    {
        lock (_lock)
        {
            _counter++;
            ($"Counter: {_counter}");
        }
    }
}
lock