System.Threading.Semaphore Class

Represents a System.Threading.WaitHandle that restricts the number of threads that can access a resource or pool of resources simultaneously.

Namespace: System.Threading
Assembly: System.Threading.dll

Syntax

public sealed class Semaphore : System.Threading.WaitHandle

Remarks

A semaphore is a synchronization primitive that allows a specified number of threads to access a shared resource. It maintains a count. Each thread that enters the semaphore decrements the count. When the count reaches zero, subsequent threads attempting to enter the semaphore are blocked until the count becomes greater than zero. A thread that exits the semaphore increments the count.

The Semaphore class is useful for controlling access to a limited number of resources, such as database connections or memory buffers. It provides a mechanism to prevent too many threads from consuming these resources concurrently, which could lead to performance degradation or errors.

For scenarios requiring a lighter-weight semaphore, consider using System.Threading.SemaphoreSlim, which is optimized for single-process synchronization and does not involve the overhead of operating system semaphores.

Constructors

Constructor Description
Semaphore(int initialCount) Initializes a new instance of the Semaphore class with the specified initial count. The initial count specifies the number of threads that can enter the semaphore without blocking.
Semaphore(int initialCount, int maximumCount) Initializes a new instance of the Semaphore class with the specified initial and maximum counts.
Semaphore(int initialCount, int maximumCount, string name) Initializes a new instance of the Semaphore class with the specified initial and maximum counts and a name. This constructor is primarily used for creating named semaphores that can be accessed across processes.
Semaphore(int initialCount, int maximumCount, string name, out bool createdNew) Initializes a new instance of the Semaphore class with the specified initial and maximum counts and a name, and indicates whether a new semaphore was created.

Methods

Method Description
WaitOne() Waits until the current thread can enter the semaphore. The method returns true if the thread successfully entered the semaphore, and false if the wait timed out.
WaitOne(int millisecondsTimeout) Waits until the current thread can enter the semaphore, using a specified time-out interval.
WaitOne(TimeSpan timeout) Waits until the current thread can enter the semaphore, using a specified time-out interval.
WaitAny(WaitHandle[] waitHandles) Waits for any one of the elements in the specified array to receive a signal.
WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) Waits for any one of the elements in the specified array to receive a signal, using a specified time-out interval.
WaitAny(WaitHandle[] waitHandles, TimeSpan timeout) Waits for any one of the elements in the specified array to receive a signal, using a specified time-out interval.
Release() Increments the semaphore's count. This allows another thread to enter the semaphore.
Release(int releaseCount) Increments the semaphore's count by the specified value. This allows up to releaseCount threads to enter the semaphore.
Dispose() Releases all resources used by the current Semaphore instance.

Methods Inherited from System.Threading.WaitHandle

The Semaphore class inherits methods like Close(), Handle, and others from the System.Threading.WaitHandle base class.

Example Usage

Tip: Always ensure that you call Release() for every successful call to WaitOne() to prevent deadlocks and semaphore starvation. Using a try-finally block or a using statement with the semaphore can help manage this reliably.
using System;
using System.Threading;

public class SemaphoreExample
{
    // A semaphore that allows at most 3 threads to access a resource concurrently.
    private static Semaphore _pool;

    public static void Main(string[] args)
    {
        // Initialize the semaphore with a maximum count of 3.
        _pool = new Semaphore(3, 3);

        Console.WriteLine("Starting worker threads...");

        // Create and start 10 worker threads.
        for (int i = 1; i <= 10; i++)
        {
            Thread worker = new Thread(new ParameterizedThreadStart(Worker));
            worker.Start(i);
        }

        Console.WriteLine("All worker threads started.");
        Console.ReadKey(); // Keep the console open
    }

    private static void Worker(object id)
    {
        Console.WriteLine($"Thread {id}: Waiting to enter the pool...");

        // Wait until a slot is available.
        _pool.WaitOne();

        Console.WriteLine($"Thread {id}: Entered the pool. Working...");

        // Simulate some work.
        Thread.Sleep(2000);

        Console.WriteLine($"Thread {id}: Exiting the pool.");

        // Release the semaphore slot.
        _pool.Release();
    }
}

See Also