Integer variables for controlling access to shared resources
Semaphores are synchronization primitives introduced by Edsger Dijkstra that provide a robust solution to the critical section problem and other synchronization challenges. A semaphore is an integer variable that, apart from initialization, is accessed only through two atomic operations: wait (or P) and signal (or V). The wait operation decrements the semaphore value and if it becomes negative, blocks the process. The signal operation increments the semaphore value and if there are waiting processes, wakes one up. Semaphores can be used for two main purposes: mutual exclusion (using binary semaphores/mutexes with initial value 1) and resource counting (using counting semaphores with initial value N representing available resources). Operating systems implement semaphores using various approaches including busy waiting (spinlocks) or blocking (putting processes to sleep). Modern systems typically use blocking semaphores to avoid wasting CPU cycles. Semaphores are versatile tools that can solve various synchronization problems including producer-consumer, reader-writer, and dining philosophers. However, they require careful usage as incorrect implementation can lead to deadlocks or starvation. Most programming languages and operating systems provide built-in semaphore implementations that handle the low-level details of atomic operations and process blocking, making them accessible to application developers for solving complex synchronization problems.