joydip_kanjilal
Contributor

My two cents on Mutex and Semaphore in C#

opinion
Jun 23, 20164 mins
Software Development

Take advantage of Mutex for inter process synchronization and Semaphore to limit concurrent access to a shared resource in your application

Thread synchronization is used to prevent multiple threads from accessing a shared resource concurrently. Mutex and Semaphore are two of the most important related concepts. Let’s understand what both of these are and when should we should use them.

Before we begin our discussion, let’s take a quick look at the basic concepts. A thread is the smallest unit of execution within a process. Essentially, multi-threading helps you to perform several tasks simultaneously and hence increase the application’s overall throughput.

A Mutex is a synchronization primitive that can work across processes — i.e., it can be used for inter process synchronization. A Semaphore on the contrary is one that allows you to limit the number of threads that have access to a shared resource at the same point of time. In essence, a Semaphore is a more generalized form of a Mutex.

A Semaphore is used to limit the number of threads that can have access to a shared resource concurrently. In essence, it is used to limit the number of consumers for a particular shared resource concurrently. You can take advantage of Semaphore to implement non-exclusive locking and hence limit concurrency.

Note that a Mutex is used for exclusive locking on a shared resource. In other words, a Mutex enables you to acquire a mutually exclusive lock – any one thread would have access to a shared resource at a given point of time. Exclusive locking is used to ensure that at any given point of time, one and only one thread can enter a critical section. A critical section may be defined as a data structure or a resource that is shared by multiple threads but one and only one thread can have access to it at any given point of time.

The System.Threading.Mutex class represents a Mutex and the System.Threading.Semaphore class is used for working with Semaphores. You can use the WaitOne method on an instance of the Mutex class to lock and use the ReleaseMutex method to unlock.

Mutex mutexObject = new Mutex(false, "Demo");

if (!mutexObject.WaitOne(TimeSpan.FromSeconds(10), false))

     {

             Console.WriteLine("Quitting for now as another instance is in execution...");

               return;

     }

To create a Semaphore in C#, you should create an instance of the Semaphore class. When creating a Semaphore instance, you need to pass two arguments to its argument constructor. While the first argument is used to indicate the number of initial resource entries, the second argument is used to specify the maximum number of concurrent resource entries. Note that if you would like to reserve all slots for the new threads that would be created, you should specify identical values for both these parameters. The following code snippet illustrates how you can create a semaphore in C#.

public static Semaphore threadPool = new Semaphore(3, 5);

Refer to the code snippet given above. The above statement creates a semaphore object named threadPool that can support a maximum of 5 concurrent requests. Note that the initial count is set to 3 as indicated in the first parameter to the constructor. This implies that 2 slots are reserved for the current thread and 3 slots are available for other threads. Let’s now write some code!

The following code snippet shows how you can create and start 10 threads using the Thread class available in the System.Threading namespace. Note how the ThreadStart delegate has been used.

for (int i = 0; i < 10; i++)

{

   Thread threadObject = new Thread(new ThreadStart(PerformSomeWork));

   threadObject.Name = "Thread Name: " + i;

   threadObject.Start();

}

Here’s the code of the PerformSomeWork method. This is the method that actually contains the code for working with semaphores.

private static void PerformSomeWork()

       {

           threadPool.WaitOne();

           Console.WriteLine("Thread {0} is inside the critical section...", Thread.CurrentThread.Name);

           Thread.Sleep(10000);

           threadPool.Release();

       }

Refer to the PerformSomeWork method given above. The WaitOne method is called on the Semaphore instance to block the current thread until a signal is received. The Release method is called on the same instance to release the semaphore. Here’s the complete code listing for your reference.

class SemaphoreDemo

   {

       public static Semaphore threadPool = new Semaphore(3, 5);

       public static void Main(string[] args)

       {

           for (int i = 0; i < 10; i++)

           {

               Thread threadObject = new Thread(new ThreadStart(PerformSomeWork));

               threadObject.Name = "Thread Name: " + i;

               threadObject.Start();

           }

           Console.ReadLine();

       }

       private static void PerformSomeWork()

       {

           threadPool.WaitOne();

           Console.WriteLine("Thread {0} is inside the critical section...", Thread.CurrentThread.Name);

           Thread.Sleep(10000);

           threadPool.Release();

       }

   }

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author