C# Threading: Semaphore

September 18, 2010 by C#   Threading  

In previous posts we had a quick look at the Mutex / Monitor classes, which limit our apps to only allow one thread to access a resource (critical section) at a time.

But what about scenarios where we work with a pool of resources? In scenarios where we need to limit the number of threads that uses a pool of resources.

One solution would be to simply modify a mutex/monitor to almost act like traffic control. Observe the following rather dodgy snippet that attempts to solve this problem (don't use)

using System;
using System.Threading;
using System.Linq;

public class Program
{
    static int _maximumThreads = 3;
    static object locker = new object();

    static void WaitOne()
    {
        while (true)
        {
            lock (locker)
            {
                if (_maximumThreads > 0)
                {
                    _maximumThreads--;
                    break;
                }
            }
        }
    }

    static void Release()
    {
        lock (locker)
        {
            _maximumThreads++;
        }
    }

    public static void Worker()
    {
        WaitOne();
        Console.WriteLine("{0} Enters", Thread.CurrentThread.Name);
        Thread.Sleep(3000);
        Console.WriteLine("{0} Exists", Thread.CurrentThread.Name);
        Release();
    }

    public static void Main(string[] args)
    {
        for (int i = 0; i < 8; i++)
        {
            Thread thread = new Thread(Worker);
            thread.Name = String.Concat("Thread ", i + 1);
            thread.Start();
        }
    }
}

We start out with an initial thread limit of three - which means we only want three threads to enter the resource pool at a time (regulate our traffic).

Within the WaitOne method we decrement the number of allowed threads and simulate some work using the Thread.Sleep method and once we're done we call the Release method where we increment our number of threads (since we're essentially done with that slot - making it available again).

Fortunately there is a much simpler/cleaner way to do this - Microsoft added a Semaphore class to .net to aid is in this process, in the following snippet we rewrite the snippet using the Semaphore class.
using System;
using System.Threading;
using System.Linq;

public class Program
{
    private static Semaphore _resourcePool;
    private static int _maximumThreads = 3;

    public static void Main(string[] args)
    {
        _resourcePool = new Semaphore(0, _maximumThreads);

        for (int i = 0; i < 8; i++)
        {
            Thread thread = new Thread(Worker);
            thread.Name = String.Concat("Thread ", i + 1);
            thread.Start();
        }
        _resourcePool.Release(_maximumThreads);
    }

    private static void Worker()
    {
        _resourcePool.WaitOne();
        Console.WriteLine("{0} Enters", Thread.CurrentThread.Name);

        Thread.Sleep(3000);

        Console.WriteLine("{0} Exits", Thread.CurrentThread.Name);
        _resourcePool.Release();
    }
}

Note that Initially the main thread owns all slots in the Semaphore, that is why we need to call the Release method in the main thread.

The Semaphore class is similar to the Mutex class in that it allows you to create named and unnamed Semaphores, which means that we can limit our resource pool cross application processes like we can do with the Mutex class.

Additional Reading:
http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx


Leave a Comment


July 23, 2013 by Anonymous

From what i 've see so far, this the best example ever. Thanks :)