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(); } } Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos