E. W. Dijkstra devised the concept of a semaphore in the 1960s. Dijkstra thought about the semaphores in use by railroad lines to guard sections of track from concurrent access by trains, thus preventing train wrecks. In software a semaphore will guard a resource by only allowing some maximum number of threads to access the resource concurrently - other threads are blocked and need to wait.
If you want to learn more about semaphores, look in the MSDN documentation for CreateSemaphore – it’s part of the Win32 API. There are two ways get semaphore behavior in .NET. One is to write P/Invoke wrappers for the Win32 API in Kernel32. Another way is to write a managed component using synchronization primitives from the CLR. For example:
public class Semaphore { public Semaphore(int count) { this.count = count; } public void Wait() { lock(this) { while(count == 0) { Monitor.Wait(this); } count--; } } public void Pulse() { lock(this) { count++; Monitor.Pulse(this); } } protected int count; }
You’ll need to write P/Invoke wrappers if you need the additional capabilities offered by a true Win32 Semaphore. For example, a named semaphore that you can use across processes.
Trivia:
I’ve seen many a computer science textbook where the Wait method has the name P, and the Pulse method has the name V. Even today you’ll see libraries where the semaphore implementation has P and V methods. It always seemed rather cryptic to me but I understood these were the names Dijkstra himself gave the methods. I figured it was the 60s, bits were expensive, and poor Dijkstra probably had to punch out cards himself to write the functions. Since then I have learned P was short for the Dutch word proberen, meaning “to test”, and V was short for verhogen, meaning “increment”.