Semaphore : Limit execution of a block of code to a set of threads

What is Semaphore ?


In computing, a 𝘀𝗲𝗺𝗮𝗽𝗵𝗼𝗿𝗲 is a synchronization primitive that allows multiple threads to coordinate and communicate with each other in a concurrent environment.

In .NET, 𝗦𝗲𝗺𝗮𝗽𝗵𝗼𝗿𝗲 is a class that is provided by the 𝗦𝘆𝘀𝘁𝗲𝗺.𝗧𝗵𝗿𝗲𝗮𝗱𝗶𝗻𝗴 namespace and is used to control access to a limited resource. It can be used to limit the number of threads that can access a shared resource at any given time, which helps to prevent issues like race conditions, deadlocks, and resource starvation.

The 𝗦𝗲𝗺𝗮𝗽𝗵𝗼𝗿𝗲 class has a constructor that takes two parameters: the initial number of available resources and the maximum number of resources that can be allocated at any given time.

Analogy

Think of a semaphore as a traffic signal at an intersection. The intersection represents a shared resource that multiple cars (threads) want to access.

When the traffic signal is green, it means that the intersection is available for cars to pass through. Similarly, when a semaphore has available resources, it means that a thread can access the shared resource.

However, when the traffic signal is red, it means that the intersection is not available for cars to pass through. Similarly, when a semaphore has no available resources, it means that a thread must wait until a resource becomes available before it can access the shared resource.

By limiting the number of cars that can pass through the intersection at any given time, the traffic signal helps to prevent accidents and ensure a smooth flow of traffic. Similarly, by limiting the number of threads that can access a shared resource at any given time, a semaphore helps to prevent issues like race conditions, deadlocks, and resource starvation.

𝗣𝗿𝗶𝗻𝘁𝗲𝗿 𝗨𝘀𝗲 𝗰𝗮𝘀𝗲

Imagine that you have a printer object that multiple threads can access in your .NET application. However, you want to ensure that only a certain number of threads can access the printer at any given time, to avoid problems like paper jams and other errors.

You can use a Semaphore to achieve this. You create a Semaphore object with a specified number of « slots », which represent the maximum number of threads that can access the printer at any given time. For example, if you want to limit access to the printer to only two threads at a time, you can create a Semaphore object with an initial count of 3 and a maximum count of 3.

Semaphore semaphore = new Semaphore(3, 3);

When a thread wants to access the printer, it calls WaitOne() on the Semaphore object. If there are available slots (i.e., if the Semaphore object’s count is greater than zero), the thread can access the printer. However, if there are no available slots (i.e., if the Semaphore object’s count is zero), the thread will be blocked and put into a queue until a slot becomes available.

semaphore.WaitOne();

Once a thread has finished using the printer, it calls Release() on the Semaphore object to signal that it’s done and to make the slot available for another thread.

class Program
{
    static void Main(string[] args)
    {
        Semaphore semaphoreObject = new Semaphore(initialCount: 3, maximumCount: 3, name: "PrinterApp");
        Printer printerObject = new Printer();

        for (int i = 0; i < 20; ++i)
        {
            int j = i;
            Task.Factory.StartNew(() =>
                {
                    semaphoreObject.WaitOne();
                    printerObject.Print(j);
                    semaphoreObject.Release();
                });
        }
        Console.ReadLine();
    }
}

class Printer
{
    public void Print(int documentToPrint)
    {
        Console.WriteLine("Printing document: " + documentToPrint);
        //code to print document
        Thread.Sleep(TimeSpan.FromSeconds(5));
    }
}

By using a Semaphore to control access to the printer, you ensure that only a limited number of threads can access the printer at any given time, which helps to prevent problems and errors. It’s like having a traffic light at a busy intersection: only a limited number of cars can pass through the intersection at a time, to avoid accidents and congestion.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *