Semaphore in C#

A Semaphore in C# is a synchronization primitive that controls access to a pool of resources by allowing a specified number of threads to enter a critical section simultaneously. It maintains a count of available permits and blocks threads when the limit is reached.

The System.Threading.Semaphore class provides all the methods and properties needed to implement semaphore functionality in multithreaded applications.

Syntax

The basic syntax for creating a semaphore −

Semaphore semaphore = new Semaphore(initialCount, maximumCount);

To acquire and release the semaphore −

semaphore.WaitOne();    // Acquire the semaphore
// Critical section code
semaphore.Release();    // Release the semaphore

Parameters

  • initialCount − The initial number of requests for the semaphore that can be granted concurrently.

  • maximumCount − The maximum number of requests for the semaphore that can be granted concurrently.

  • name (optional) − The name of a system semaphore object for named semaphores.

Semaphore Constructors

Constructor Description
Semaphore(Int32, Int32) Initializes a new instance specifying initial and maximum concurrent entries.
Semaphore(Int32, Int32, String) Initializes a new instance with optional name for system semaphore object.
Semaphore(Int32, Int32, String, Boolean) Initializes a new instance with name and variable indicating if new system semaphore was created.

Semaphore with Count = 2 Critical Section (Max 2 Threads) T1 T2 T3 T4 Active (2/2) Waiting T1 and T2 are executing, T3 and T4 are blocked

Using Semaphore for Thread Synchronization

Example

using System;
using System.Threading;

class Demo {
    static Thread[] threads = new Thread[5];
    static Semaphore semaphore = new Semaphore(2, 2);
    
    static void DoSomething() {
        Console.WriteLine("{0} = waiting", Thread.CurrentThread.Name);
        semaphore.WaitOne();
        Console.WriteLine("{0} begins!", Thread.CurrentThread.Name);
        Thread.Sleep(1000);
        Console.WriteLine("{0} releasing...", Thread.CurrentThread.Name);
        semaphore.Release();
    }
    
    static void Main(string[] args) {
        for (int j = 0; j < 5; j++) {
            threads[j] = new Thread(DoSomething);
            threads[j].Name = "Thread-" + j;
            threads[j].Start();
        }
        
        foreach (Thread t in threads) {
            t.Join();
        }
        
        Console.WriteLine("All threads completed");
    }
}

The output of the above code is −

Thread-0 = waiting
Thread-1 = waiting
Thread-2 = waiting
Thread-3 = waiting
Thread-4 = waiting
Thread-0 begins!
Thread-1 begins!
Thread-0 releasing...
Thread-1 releasing...
Thread-2 begins!
Thread-3 begins!
Thread-2 releasing...
Thread-3 releasing...
Thread-4 begins!
Thread-4 releasing...
All threads completed

Semaphore with Different Count Values

Example

using System;
using System.Threading;

class ResourcePool {
    static Semaphore semaphore = new Semaphore(1, 3); // Start with 1, max 3
    
    static void AccessResource(object id) {
        Console.WriteLine("Thread {0} requesting access", id);
        semaphore.WaitOne();
        
        Console.WriteLine("Thread {0} has entered the pool", id);
        Thread.Sleep(2000);
        Console.WriteLine("Thread {0} is leaving the pool", id);
        
        semaphore.Release();
    }
    
    static void Main() {
        for (int i = 1; i <= 4; i++) {
            Thread t = new Thread(AccessResource);
            t.Start(i);
        }
        
        Thread.Sleep(8000);
        Console.WriteLine("Main thread finished");
    }
}

The output of the above code is −

Thread 1 requesting access
Thread 2 requesting access
Thread 3 requesting access
Thread 4 requesting access
Thread 1 has entered the pool
Thread 1 is leaving the pool
Thread 2 has entered the pool
Thread 2 is leaving the pool
Thread 3 has entered the pool
Thread 3 is leaving the pool
Thread 4 has entered the pool
Thread 4 is leaving the pool
Main thread finished

How It Works

A semaphore maintains an internal counter that gets decremented when WaitOne() is called and incremented when Release() is called. When the counter reaches zero, subsequent calls to WaitOne() block until another thread calls Release().

Conclusion

Semaphores in C# provide an effective way to control concurrent access to shared resources by limiting the number of threads that can enter a critical section simultaneously. They are essential for managing thread pools and preventing resource contention in multithreaded applications.

Updated on: 2026-03-17T07:04:35+05:30

4K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements