Thread synchronization in c#

 

  1. Lock: The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement, and then releasing the lock. Here’s an example:
class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}
  1. Mutex: A Mutex is similar to a lock but it can work across multiple processes. Here’s an example:
class Program
{
    static void Main()
    {
        using (Mutex mutex = new Mutex(false, "MyMutex"))
        {
            if (!mutex.WaitOne(5000, false))
            {
                Console.WriteLine("Another instance is running. Bye!");
                return;
            }
            RunProgram();
        }
    }

    static void RunProgram()
    {
        Console.WriteLine("Running. Press Enter to exit");
        Console.ReadLine();
    }
}
  1. Monitor: Monitor is similar to lock but it has additional functionality. It has Wait, Pulse and PulseAll methods for signaling. Here’s an example:
class Worker
{
    private readonly object _locker = new object();
    private bool _go;

    public void Work()
    {
        lock (_locker)
        {
            while (!_go)
            {
                Monitor.Wait(_locker); // Wait for the go signal
            }
            Console.WriteLine("Working...");
        }
    }

    public void Go()
    {
        lock (_locker)
        {
            _go = true;
            Monitor.Pulse(_locker); // Notify the waiting thread
        }
    }
}
  1. AutoResetEvent: AutoResetEvent is a signaling construct. When signaled, it releases a single waiting thread. It then automatically returns to the non-signaled state. Here’s an example:
AutoResetEvent autoEvent = new AutoResetEvent(false);

public void Work()
{
    Console.WriteLine("Waiting...");
    autoEvent.WaitOne(); // Wait for the signal
    Console.WriteLine("Signal received!");
}

public void Signal()
{
    autoEvent.Set(); // Send the signal
}
  1. ManualResetEvent: ManualResetEvent is similar to AutoResetEvent, but when it is signaled, it releases all waiting threads. It remains signaled until it is manually reset. Here’s an example:
ManualResetEvent manualEvent = new ManualResetEvent(false);

public void Work()
{
    Console.WriteLine("Waiting...");
    manualEvent.WaitOne(); // Wait for the signal
    Console.WriteLine("Signal received!");
}

public void Signal()
{
    manualEvent.Set(); // Send the signal
}

 6. Semaphores: A semaphore is a synchronization primitive that controls access to a common resource by multiple processes in a concurrent system such as a multitasking operating system. A semaphore has a set of permits. A thread can acquire a permit from the semaphore, reducing the number of available permits. If no permits are available, the thread will block until a permit becomes available (or until interrupted). When the thread has finished with the permit, it can release it back to the semaphore, increasing the number of available permits. Here’s an example in C#:

using System;
using System.Threading;

class Program
{
    static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(3);

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

    static void Enter(object id)
    {
        Console.WriteLine(id + " wants to enter");
        semaphoreSlim.Wait();
        Console.WriteLine(id + " is in!"); // Only three threads can be here at once.
        Thread.Sleep(1000 * (int)id);
        Console.WriteLine(id + " is leaving");
        semaphoreSlim.Release();
    }
}
  1. ReadWriteLocks: A ReadWriteLock allows concurrent read access to an object but requires exclusive access for write operations. Multiple threads can read the data in parallel but an exclusive lock is needed for writing or modifying data. When a writer is writing the data, all other writers or readers will be blocked until the writer is finished. Here’s an example in C#:
using System;
using System.Threading;

class Program
{
    static ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();

    static void Main()
    {
        // Start a new thread that reads the data.
        new Thread(Read).Start();

        // Start a new thread that writes the data.
        new Thread(Write).Start("Thread 1");
        new Thread(Write).Start("Thread 2");
    }

    static void Read()
    {
        while (true)
        {
            rwl.EnterReadLock();
            try
            {
                // ... read from shared resource
            }
            finally
            {
                rwl.ExitReadLock();
            }
        }
    }

    static void Write(object threadID)
    {
        while (true)
        {
            rwl.EnterWriteLock();
            try
            {
                // ... write to shared resource
                Console.WriteLine($"{threadID} is writing");
                Thread.Sleep(1000);
            }
            finally
            {
                rwl.ExitWriteLock();
            }
        }
    }
}


Vikash Chauhan

C# & .NET experienced Software Engineer with a demonstrated history of working in the computer software industry.

Post a Comment

Previous Post Next Post

Contact Form