Facebook Pixel

Binary Semaphores in Operating Systems

Semaphores come in two flavors: counting semaphores and binary semaphores. This lesson focuses on binary semaphores specifically, which are the simpler of the two and arguably the most commonly used when you just need to protect a single shared resource.

What a Binary Semaphore Actually Is

A binary semaphore can only ever hold one of two values: 0 or 1. That is it. When the value is 1, the resource is free and a process can go ahead and use it. When it is 0, the resource is occupied and anyone else trying to get in has to wait.

The two operations that make this work are wait and signal.

wait(S)

Wait checks the semaphore value. If it is greater than zero, the process proceeds and the value drops to 0. If it is already 0, the process blocks until the value becomes 1 again.

c
wait(S) {
    while (S <= 0);   // Block: resource is occupied
    S--;              // Claim the resource (S goes from 1 to 0)
}

signal(S)

Signal is what a process calls when it is done. It bumps the value back up to 1, which lets the next waiting process through.

c
signal(S) {
    S++;              // Release the resource (S goes from 0 to 1)
}

Walking Through How It Works

Say you have two processes, P1 and P2, both needing access to the same resource. The semaphore starts at 1.

text
Initial: S = 1  (resource is free)

Step 1:  P1 calls wait(S)   -> S = 0   -> P1 enters critical section
Step 2:  P2 calls wait(S)   -> S is 0  -> P2 BLOCKS (waits)

         ... P1 does its work ...

Step 3:  P1 calls signal(S) -> S = 1   -> P2 gets unblocked
Step 4:  P2 calls wait(S)   -> S = 0   -> P2 enters critical section

         ... P2 does its work ...

Step 5:  P2 calls signal(S) -> S = 1   -> Resource is free again

It is a clean, orderly handoff between processes. At no point are both P1 and P2 inside the critical section simultaneously.

Implementation in C++

cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>

class BinarySemaphore {
private:
    int value;
    std::mutex mtx;
    std::condition_variable cv;

public:
    BinarySemaphore() : value(1) {}    // Initialize to 1 (free)

    void wait() {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this]() { return value == 1; });
        value = 0;                      // Resource is now taken
        std::cout << "Resource acquired. Semaphore value: " << value << std::endl;
    }

    void signal() {
        std::unique_lock<std::mutex> lock(mtx);
        value = 1;                      // Resource is now free
        std::cout << "Resource released. Semaphore value: " << value << std::endl;
        cv.notify_one();
    }

    int getValue() { return value; }
};

BinarySemaphore sem;

void process(int id) {
    std::cout << "Process " << id << " trying to enter critical section." << std::endl;

    sem.wait();     // Entry section

    // --- Critical Section ---
    std::cout << "Process " << id << " is in the critical section." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(800));
    std::cout << "Process " << id << " is leaving the critical section." << std::endl;

    sem.signal();   // Exit section
}

int main() {
    std::cout << "Initial semaphore value: " << sem.getValue() << std::endl;

    std::thread p1(process, 1);
    std::thread p2(process, 2);
    std::thread p3(process, 3);

    p1.join();
    p2.join();
    p3.join();

    std::cout << "All processes completed." << std::endl;
    std::cout << "Final semaphore value: " << sem.getValue() << std::endl;
    return 0;
}

Output:

text
Initial semaphore value: 1

Process 1 trying to enter critical section.
Resource acquired. Semaphore value: 0
Process 1 is in the critical section.

Process 2 trying to enter critical section.
Process 3 trying to enter critical section.

Process 1 is leaving the critical section.
Resource released. Semaphore value: 1
Resource acquired. Semaphore value: 0
Process 2 is in the critical section.
Process 2 is leaving the critical section.
Resource released. Semaphore value: 1
Resource acquired. Semaphore value: 0
Process 3 is in the critical section.
Process 3 is leaving the critical section.
Resource released. Semaphore value: 1

All processes completed.
Final semaphore value: 1

Process 1 gets in first, Processes 2 and 3 wait. As soon as 1 signals, the next one gets through. They take turns cleanly with no overlap.

Binary vs Counting Semaphore

FactorBinary SemaphoreCounting Semaphore
Values it can holdOnly 0 or 1Any non-negative integer
Use caseSingle resource accessMultiple instances of a resource
ComplexitySimplerSlightly more complex
Mutual ExclusionYes, strictly one process at a timeDepends on the count value
ExampleSingle printer, single fileThread pool, connection pool

The binary semaphore is essentially the simplest possible lock. You do not need it to count anything beyond free or occupied. For situations where exactly one process should be in the critical section at a time and there is only one instance of the resource, it is usually the right tool for the job.

When you have multiple identical resources and need to track how many are still available, that is when you reach for a counting semaphore instead.

Binary Semaphore vs Mutex: Are They the Same?
They are very similar but not identical. A mutex has ownership: only the thread that locked it can unlock it. A binary semaphore has no such restriction. Any process can call signal() on it, even one that never called wait(). This makes binary semaphores more flexible for signaling between processes, but also slightly more dangerous because there is no enforcement of who releases the resource.

Fill in the Blank

A binary semaphore can only hold the values and . When the value is 1, the resource is free. When the value is 0, any process calling wait() will be blocked.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.