Operating System - Concept of Semaphores in process synchronization

 What is a Semaphore?

A semaphore is a synchronization tool used to manage access to shared resources in a concurrent system (e.g., multitasking OS, multithreaded applications).

It helps avoid race conditions, where multiple processes or threads access shared data at the same time in an unsafe way.

 Why Use Semaphores?

To ensure that:

  • Only one process accesses the critical section at a time (mutual exclusion).

  • Processes are synchronized (especially for tasks like producer-consumer problems).

  • Deadlocks and starvation are prevented (with proper usage).

Types of Semaphores

1. Counting Semaphore

  • Can have any non-negative integer value.

  • Used when multiple instances of a resource are available.

  • Example: managing a pool of 5 printers.

2. Binary Semaphore (also called Mutex)

  • Can have only two values: 0 or 1.

  • Acts like a simple lock: 1 means resource is free, 0 means it’s in use.

  • Used for mutual exclusion.

 How Does a Semaphore Work?

A semaphore is an integer variable that is manipulated only by two atomic operations:

wait(S) or P(S):

wait(S):
   while S <= 0:
       wait (loop or block)
   S = S - 1
  • Decreases the semaphore.

  • If S > 0, the process enters the critical section.

  • If S == 0, the process waits (gets blocked).

signal(S) or V(S):

signal(S):
   S = S + 1
  • Increases the semaphore.

  • If a process was blocked, it gets unblocked.

  • These operations must be atomic (uninterruptible).

 Example: Mutual Exclusion with a Binary Semaphore

semaphore S = 1;

Process P1:
wait(S);
// critical section
signal(S);

Process P2:
wait(S);
// critical section
signal(S);
  • Only one process can enter the critical section at a time.

  • The other will wait if S = 0.

 Advantages of Semaphores

  • Simple and powerful tool for synchronization.

  • Works for both single resource and multiple resource scenarios.

  • Can be used for signaling between processes.

Disadvantages

  • Misuse can lead to deadlock (e.g., forgetting to release a semaphore).

  • Busy waiting (in naïve implementations).

  • Hard to debug and maintain in large systems.

  • Doesn’t prevent priority inversion unless specifically handled.