Semaphores are synchronisation primitives used to manage concurrent processes by controlling access to shared resources in a computing environment. They are essential for preventing race conditions...
Semaphores are synchronisation primitives used to manage concurrent processes by controlling access to shared resources in a computing environment. They are essential for preventing race conditions, where multiple processes attempt to access and modify shared data simultaneously, leading to unpredictable outcomes.
A semaphore is essentially a variable that signals whether a particular resource is available. Using operations like wait (or P) and signal (or V), semaphores coordinate the activities of different processes, ensuring that only a specified number of processes can access the critical section at any given time. This coordination is crucial in multi-threaded applications to maintain data consistency and integrity.
Binary semaphores, also known as mutexes (mutual exclusion), have only two states: 0 and 1. They ensure that a resource is accessed by only one thread at a time. When a thread acquires the semaphore, it sets the value to 0, and when it releases the semaphore, it sets the value back to 1.
Binary semaphores are typically used for simple lock/unlock mechanisms where mutual exclusion is required.
Counting semaphores can take on any non-negative integer value and are used to control access to a resource with a limited number of instances. The semaphore's value is initialised to the number of available resources. Each wait operation decrements the value, and each signal operation increments it. If the value is zero, indicating no resources are available, the process attempting to decrement the semaphore is blocked until another process increments it.
This type of semaphore is useful in scenarios where a pool of identical resources needs to be managed, such as a fixed number of database connections.
Semaphores are often compared with other synchronisation primitives like locks, monitors, and condition variables:
However, semaphores provide a simpler and more direct way to implement certain synchronisation scenarios, especially those involving limited resource pools.
Deadlocks occur when two or more processes wait indefinitely for resources held by each other. To avoid deadlocks with semaphores, techniques such as resource ordering, timeout mechanisms, and deadlock detection algorithms can be employed. Ensuring that all semaphores are requested in a predefined global order can prevent circular wait conditions, a key factor in deadlock.
Priority inversion happens when a higher-priority task is waiting for a resource held by a lower-priority task, causing the higher-priority task to be indirectly preempted. This can be mitigated using priority inheritance protocols, where a lower-priority task temporarily inherits the higher priority of the blocked task, ensuring that critical sections are exited more quickly.
Special thanks to Gauri Tomar for contributing to this article on takeUforward. If you also wish to share your knowledge with the takeUforward fam, please check out this article.