Semaphores in C#


A short while ago I had a need to limit simultaneous requests to a web service from a multi-threaded application to prevent timeouts.  I learned about semaphores in school and knew this was the right approach, but I have never used one in a real-world application before.  Luckily, the .NET framework makes it rather easy to add a semaphore to your application with the appropriately named Semaphore class.

To use a semaphore in C#, you first need to instantiate an instance of a Semaphore object.  The constructor, at a minimum, takes two parameters.  The first is the number of resource slots initially available when the object is instantiated.  The second parameter is the maximum number of slots available.  If you want to reserve some slots for the calling thread, you can do so by making the first parameter smaller than the second.  To reserve all slots for new threads, you should make both parameters the same.

After you instantiated your Sempahore object, you simply need to call the WaitOne method when entering an area of code that you want restricted to a certain number of threads.  When processing finishes, call the Release method to release the slot back to the pool.

In the code below, we are instantiating a semaphore with a maximum of three resource slots, all of which are available at the time the semaphore is created.  If we wanted some of the semaphore’s slots to belong to the calling thread, we would simply decrease the value of the first parameter by the number of slots we want to reserve for the calling thread.

// Three reserved slots for threads
public Semaphore Pool = new Semaphore(3, 3);

In the sample code here, we are still creating a semaphore with a maximum of three resource slots, but only one of those slots is initially available.  The other two are currently reserved for the calling thread.

// One slot reserved for threads, two slots reserved for the calling thread
public static Semaphore Pool = new Semaphore(1, 3);

So now that we know how to create the semaphore object, we need to know how to use it.  The code example below should be rather straight-forward:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace SemaphoreDemo
{
    class SemaphoreExample
    {
        // Three reserved slots for threads
        public static Semaphore Pool = new Semaphore(3, 3);

        public static void Main(string[] args)
        {
            // Create and start 20 threads
            for (int i = 0; i < 20; i++)
            {
                Thread t = new Thread(new ThreadStart(DoWork));
                t.Start();
            }
            Console.ReadLine();
        }

        private static void DoWork()
        {
            // Wait on a semaphore slot to become available
            SemaphoreExample.Pool.WaitOne();

            #region Area Protected By Semaphore
            Console.WriteLine("Acquired slot...");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i + 1);
            }
            Console.WriteLine("Released slot...");
            #endregion

            // Release the semaphore slot
            SemaphoreExample.Pool.Release();
        }
    }
}

In the preceeding code, we first create and start 20 new threads.  Each of these threads runs the “DoWork” method.  Inside this method, there is a section of code that is protected by the semaphore.  In this example, a maximum of 3 threads will be allowed into the procted area at any given time.

Before entering the protected area, each thread calls the “WaitOne” method.  When a thread calls this method, it will block until it can acquire an open semaphore slot.  When it does, it can proceed and execute the code inside of the protected area.  When the thread has finished executing the code in the protected region, it executes the “Release” method to return the slot to the semaphore.  The semaphore will then allow a new thread that is waiting on the “WaitOne” method into the protected area.

That’s really all there is to semaphores in C#.  For more information, you can try the following resources:

, ,

  1. No comments yet.

You must be logged in to post a comment.