Provides more sophisticated ways for processes synchronization.
Protect a critical section by semaphore S (count) – an integer variable
Accessed via two indivisible operations wait() & signal()
S: the count variable signifies how many available spots available for critical sections
S can be higher than 1 for some operations that allow multiple processes such as I/O read.
Types of Semaphore:
Counting semaphore: integer value can range over an unrestricted domain
Binary semaphore: integer value can range only between 0 and 1, which is Mutex Lock
Implementation with Busy wait
wait(): wait while count ⇐0, then when S— when executing in CS
signal(): S++ means it is done running, so 1 more spot is available
Requirement: No two processes can execute wait() & signal() on the same semaphore at the same time
However, the busy wait is very computationally expensive
Implementation without Busy wait:
Each Semaphore has an associated waiting queue
block(): place the process invoking the operation on the waiting queue
wakeup(): remove one of processes in the waiting queue, place it in the ready queue
wait(*S):
signal(*S):
Problems with semaphore
signal(mutex) ... wait(mutex): where a process signals a mutex before waiting on it. This can lead to race conditions and incorrect behavior.
wait(mutex) ... wait(mutex): Multiple processes waiting on the same mutex without releasing it can cause a deadlock.
Difficult to detect
Omitting of wait(mutex) and/or signal(mutex): If a process forgets to wait on a mutex before accessing a shared resource, it can violate mutual exclusion and lead to inconsistencies.