An alternative approach, that must make use of specific system facilities is the use of the ``semaphore'' variables proposed by Dijkstra. Semaphores are (generally speaking - implementations can add details) a pair composed of an integer variable, called the semaphore counter, and of a queue (FIFO) of id.s of processes waiting to get synchronized access to the shared resource the semaphore controls. The counter is initialized to a positive value upon semaphore instantiation, and only two atomic operations can be performed on the semaphore by a process:
It's easy to see how a semaphore can be used to enforce mutual exclusion on a shared resource: a semaphore is assigned to the resource, it's shared among all processes that need to access the resource, and its counter is initialized to 1. A process then waits on the semaphore upon entering the critical section for the resource, and signals on leaving it. The first process will get access. If another process arrives while the former is still in the critical section, it'll be blocked, and so will further processes. In this situation the absolute value of the counter is equal to the number of processes waiting to enter the critical section. Every process leaving the critical section will let a waiting process use the resource by signaling the semaphore.