Search⌘ K
AI Features

Semaphore

Explore the concept of semaphores in C# as synchronization primitives that control access to resources with atomic counters. Understand their use in signaling between threads, mutual exclusion, and how to avoid issues like missed signals and race conditions. This lesson covers semaphore initialization, thread coordination, classic concurrency problems, and differences between local and system semaphores, helping you apply semaphores effectively in C# concurrency scenarios.

Semaphore

Semaphores are one of the oldest synchronization primitives, invented by Edsger Dijkstra. A semaphore is nothing more than an atomic counter that gets incremented by one whenever Release() is invoked and decremented by one whenever WaitOne() is called. The semaphore is initialized with an initial count value. The count value specifies the maximum permits available to give out. We can create a Semaphore object as follows:

Semaphore semaphore = new Semaphore(0, 1);

The first argument is the number of permits to start the semaphore with and the second argument is the maximum number of permits the semaphore can hold.

SemaphoreFullException is thrown if Release() is invoked on a semaphore object that already has reached its maximum count. This is demonstrated in the snippet below:

C#
using System;
using System.Threading;
class Demonstration
{
static void Main()
{
Semaphore sem = new Semaphore(0,1);
sem.Release();
sem.Release();
}
}

Semaphores can be used in versatile ways. The primary use of semaphores is to signal among threads that are working to achieve a common goal.

We can use a semaphore object with an initial count of one for implementing mutual exclusion. Consider the snippet below:

C#
Mutex mutex = new Mutex();
mutex.WaitOne();
// critical section
mutex.ReleaseMutex();
...