Vaidikalaya

Semaphores In Process Synchronization


A semaphore is an operating-system–based synchronization mechanism. It is implemented in the kernel and exposed through system calls/APIs so that processes and threads can safely coordinate access to shared resources, ensuring consistency and preventing race conditions and deadlocks.

A semaphore is indeed an integer variable used to control access to shared resources in a concurrent (multi-process or multi-threaded) system. It ensures that only the permitted number of processes can access the resource at a time.


A semaphore works using two fundamental operations:

1. Wait
  • It also known as P, down, or acquire.
  • Decreases the semaphore value.
  • If the value becomes negative, the process is blocked until the resource becomes available.
wait(S)
{
   while (S<=0);
   S--;
}

2. Signal 
  • It also known as V, up, or release.
  • Increases the semaphore value.
  • If there are waiting processes, one of them gets unblocked.
signal(S)
{
   S++;
}

Types of Semaphore

Semaphores are mainly of two Types:

1. Counting Semaphore

A counting semaphore is a type of semaphore used in operating systems to manage access to a resource that has multiple identical instances. It allows more than one process or thread to access the resource at the same time—up to a specified limit. Its value (count) can range over non-negative integers: 0, 1, 2, … etc.

  • If the count is greater than 0, a process can access the resource, and the count is decremented.
  • If the count is 0, all resources are in use, and any process calling wait() will block until some process releases a resource (calls signal()).
  • A counting semaphore is typically used for sequencing processes or managing multiple identical resources, because it can start at zero and be signaled to control the order or number of operations that proceed.
  • It use for multiple printers, multiple database connections
2. Binary Semaphore

A binary semaphore is the simplest kind of semaphore, used when only one instance of a resource exists. It can have only two possible values: 0 or 1 — which is why it’s called binary. It works like a lock: either the resource is free (1) or busy (0). 1 means the resource is free, and 0 means the resource is locked or in use.

  • Binary semaphore is usually for mutual exclusion (critical-section locking), where only one process can access the resource at a time.
  • It use for single printer, single shared variable.

Semaphore as a Sequencer

A semaphore can be used as a sequencer to control the order of execution of processes or threads. This is done by initializing the semaphore and using wait() and signal() so that one process cannot start until another has finished a required step.

Example: Suppose we need to calculate the cost of painting a circle. First we need its radius, then we compute the area, and finally we calculate the cost. so the steps happen strictly in order:

process 1 -> process 2 -> process 3
Get radius → Calculate area → Calculate cost

Problem Setup
  • Process 1: Reads the radius of a circle.
  • Process 2: Waits for the radius, computes the area.
  • Process 3: Waits for the area, computes the cost of painting the circle.

We use two semaphores S1 & S2.

P1 (set S1=0, S2=0 So First run P1)
Process1() {
    print("Enter radius: ");
    radius = read_input();
    signal(S1);        
//Tell Process 2 radius is ready
}

P2 (wait unit S1=1)
Process2() {
//Wait until radius is available
   wait(S1);          
   area = 3.14159 * radius * radius;
   signal(S2);        
//Tell Process 3 area is ready
}
P3 (wait until S2=1)
Process3() {
//Wait until area is available
    wait(S2);          
    cost = area * RATE;
    print("Total cost: ", cost);
}


Advantages of Semaphores

  • Semaphores allow only one process into the critical section. They follow the mutual exclusion principle strictly and are much more efficient than some other methods of synchronization.
  • There is no resource wastage because of busy waiting in semaphores as processor time is not wasted unnecessarily to check if a condition is fulfilled to allow a process to access the critical section.
  • Semaphores are implemented in the machine independent code of the microkernel. So they are machine independent.
  • It Scalable to multiple resources because counting semaphores easily manage a fixed pool of resources such as database connections, network sockets, or printers.
  • Foundation for higher-level constructs: Mutexes, condition variables, and monitors can all be built using semaphores.

Disadvantage of Semaphores

  • Risk of deadlock: If processes wait on each other’s semaphores in the wrong order, they can block forever.
  • Priority Inversion: Semaphores may lead to a priority inversion where low priority processes may access the critical section first and high priority processes later.
  • Programming complexity: Developers must manually ensure correct pairing of wait and signal. A single missing or extra call can cause serious bugs like deadlocks or resource leaks.

Semaphores are a flexible, low-level synchronization tool that can solve a wide range of concurrency problems and manage multiple identical resources. However, they require careful programming: mismanagement can lead to deadlocks, starvation, or subtle race conditions.