Counting Semaphores: Managing Concurrent Resource Access in Operating Systems

Understand how counting semaphores control concurrent access to shared resources. This tutorial explains their functionality, implementation using `Down()` and `Up()` operations, and how they differ from binary semaphores, providing a robust mechanism for managing multiple processes or threads accessing a critical section.



Counting Semaphores for Concurrent Access to Resources

Understanding Counting Semaphores

A counting semaphore is a synchronization primitive used in operating systems to control access to shared resources among multiple processes or threads. Unlike a binary semaphore (which only allows 0 or 1 process access), a counting semaphore can allow multiple processes to enter a critical section (a section of code accessing a shared resource) concurrently, up to a predefined limit. This is a very powerful tool for coordinating access to resources in situations where multiple processes need to use the same resource but should not access it simultaneously.

Implementing a Counting Semaphore

A counting semaphore can be implemented using a structure like this:

Semaphore Structure

struct Semaphore {
  int value; // Number of processes that can be in critical section.
  queueType L; // Queue of blocked processes.
};

value represents the number of available slots in the critical section. L is a queue of processes blocked because the critical section is full.

Semaphore Operations: Down and Up

Down Operation

void Down(Semaphore &S) {
  S.value--;
  if (S.value < 0) {
    put_process(PCB) in L; // Block if no slots are available
    sleep();
  }
}
Up Operation

void Up(Semaphore &S) {
  S.value++;
  if (S.value <= 0) {
    select a process from L;
    wakeup(); //Wake a blocked process.
  }
}

Down() attempts to enter the critical section; Up() signals that a slot is free.

How Counting Semaphores Work

The semaphore's value indicates the number of processes allowed in the critical section. A process decrements the value before entering and increments it upon exiting.

  • If the value is negative, the process is added to the blocked queue and sleeps. This ensures that the number of processes in the critical section does not exceed the semaphore's value.
  • If the value is positive, the process enters the critical section.
  • When a process exits, it increments the semaphore. If the value was negative, it wakes up a blocked process.
  • Processes are woken up in FIFO order.

A negative semaphore value shows the number of blocked processes.