Semaphores are classified based on how their values are restricted and how they control access to resources. The type of semaphore determines whether only one process or multiple processes can access a resource at a time. Depending on system requirements, semaphores are mainly divided into two categories.

Binary Semaphore
A Binary Semaphore is a synchronization mechanism that can take only two values: 0 or 1. It is mainly used to ensure exclusive access to a critical section, allowing only one process to execute at a time. The mechanism relies on atomic wait (P) and signal (V) operations to control entry and exit.
- Value limited to 0 or 1
- Allows single-process access to critical section
- Uses atomic P and V operations
- May lead to starvation if not properly scheduled
Working of Binary Semaphore
- When the value is 1, the resource is available.
- A process performing wait (P) changes the value to 0 and gains access.
- If another process attempts access while the value is 0, it is blocked.
Code Implementation for Binary Semaphore:
#include <iostream>
using namespace std;
class BinarySemaphore {
int value;
public:
BinarySemaphore() { value = 1; }
void wait() {
if (value == 1) {
value = 0;
cout << "Resource acquired\n";
} else {
cout << "Process blocked\n";
}
}
void signal() {
value = 1;
cout << "Resource released\n";
}
};
int main() {
BinarySemaphore s;
s.wait();
s.wait();
s.signal();
}
/*package whatever //do not write package name here */
class BinarySemaphore {
private int value = 1;
public void waitSem() {
if (value == 1) {
value = 0;
System.out.println("Resource acquired");
} else {
System.out.println("Process blocked");
}
}
public void signal() {
value = 1;
System.out.println("Resource released");
}
}
public class Main {
public static void main(String[] args) {
BinarySemaphore s = new BinarySemaphore();
s.waitSem();
s.waitSem();
s.signal();
}
}
class BinarySemaphore:
def __init__(self):
self.value = 1
def wait(self):
if self.value == 1:
self.value = 0
print("Resource acquired")
else:
print("Process blocked")
def signal(self):
self.value = 1
print("Resource released")
s = BinarySemaphore()
s.wait()
s.wait()
s.signal()
class BinarySemaphore {
constructor() {
this.value = 1;
}
wait() {
if (this.value === 1) {
this.value = 0;
console.log("Resource acquired");
} else {
console.log("Process blocked");
}
}
signal() {
this.value = 1;
console.log("Resource released");
}
}
const s = new BinarySemaphore();
s.wait();
s.wait();
s.signal();
| Advantages | Disadvantages |
|---|---|
| Simple structure and easy implementation | No strict guarantee of bounded waiting |
| Provides exclusive access to shared resources | Possibility of starvation |
| Platform-independent synchronization technique | Improper usage can cause deadlock |
| Minimizes race condition risks | Frequent synchronization calls may impact performance |
Counting Semaphore
A Counting Semaphore is a synchronization mechanism that can take any non-negative integer value (0, 1, 2, 3, …). It is used to manage multiple instances of a shared resource, permitting more than one process to access the critical section depending on resource availability. Like binary semaphores, it uses atomic wait (P) and signal (V) operations.
- Accepts non-negative integer values
- Supports multiple concurrent accesses
- Operates through atomic wait and signal
- Maintains count of available resources
- Suitable for identical resource pools
Working of Counting Semaphore
- If the semaphore value is greater than 0, resources are available.
- Each wait (P) decreases the value by 1 and allows execution.
- When the value becomes 0, further requests are blocked.
- Signal (V) increases the value and resumes one waiting process.
Code Implementation for Counting Semaphores:
#include <iostream>
using namespace std;
class CountingSemaphore {
int value;
public:
CountingSemaphore(int v) { value = v; }
void wait() {
if (value > 0) {
value--;
cout << "Resource acquired\n";
} else {
cout << "Process blocked\n";
}
}
void signal() {
value++;
cout << "Resource released\n";
}
};
int main() {
CountingSemaphore s(3);
s.wait();
s.wait();
s.wait();
s.wait();
}
class CountingSemaphore {
private int value;
public CountingSemaphore(int v) {
value = v;
}
public void waitSem() {
if (value > 0) {
value--;
System.out.println("Resource acquired");
} else {
System.out.println("Process blocked");
}
}
public void signal() {
value++;
System.out.println("Resource released");
}
}
public class Main {
public static void main(String[] args) {
CountingSemaphore s = new CountingSemaphore(3);
s.waitSem();
s.waitSem();
s.waitSem();
s.waitSem();
}
}
class CountingSemaphore:
def __init__(self, value):
self.value = value
def wait(self):
if self.value > 0:
self.value -= 1
print("Resource acquired")
else:
print("Process blocked")
def signal(self):
self.value += 1
print("Resource released")
s = CountingSemaphore(3)
s.wait()
s.wait()
s.wait()
s.wait()
class CountingSemaphore {
constructor(value) {
this.value = value;
}
wait() {
if (this.value > 0) {
this.value--;
console.log("Resource acquired");
} else {
console.log("Process blocked");
}
}
signal() {
this.value++;
console.log("Resource released");
}
}
const s = new CountingSemaphore(3);
s.wait();
s.wait();
s.wait();
s.wait();
Explanation
- Whenever a process executes wait(), if resources are unavailable, it is blocked and added to the queue.
- When a process finishes and calls signal(), another waiting process is woken up to use the resource.
| Advantages | Disadvantages |
|---|---|
| Efficient management of multiple resources | More complex than binary semaphore |
| Better resource utilization | Incorrect handling may cause deadlock |
| Flexible and scalable synchronization method | Possible starvation without proper scheduling |
| Reduces idle waiting in resource pools | Requires careful coordination of operations |
Wait (P) Operation
- The wait (P) operation decreases the semaphore value by 1.
- If the value becomes negative or zero (no resources available), the process is blocked until a resource is released.
- It ensures that a process enters the critical section only when a resource is available.
Signal (V) Operation
- The signal (V) operation increases the semaphore value by 1.
- It indicates that a resource has been released.
- If any processes are waiting, one of them is awakened and allowed to proceed.