Dining Philosopher Solution using Semaphores (original) (raw)

Last Updated : 8 Jan, 2026

The Dining Philosopher Problem is a classic synchronization problem introduced by Edsger Dijkstra in 1965. It illustrates the challenges of resource sharing in concurrent programming, such as deadlock, starvation, and mutual exclusion.

os

Problem Statement

**The challenge: Design a synchronization mechanism so that philosophers can eat without causing **deadlock (all waiting forever) or **starvation (some never get a chance to eat).

Issues in the Problem

  1. **Deadlock: If every philosopher picks up their left chopstick first, no one can pick up the right one circular wait.
  2. **Starvation: Some philosophers may never get a chance to eat if others keep eating.
  3. **Concurrency Control: Must ensure no two adjacent philosophers eat simultaneously.

**Semaphore Solution to Dining Philosopher

We use **semaphores to manage chopsticks and avoid deadlock.

Algorithm

**Pseudocode

semaphore chopstick[5] = {1,1,1,1,1};

Philosopher(i):
while(true) {
think();
wait(chopstick[i]); // pick left chopstick
wait(chopstick[(i+1)%5]); // pick right chopstick

eat();

signal(chopstick[i]); // put left chopstick
signal(chopstick[(i+1)%5]); // put right chopstick

}

Explanation:

**Code

C++ `

#include #include #include #include #include <unistd.h>

#define N 5 // Number of philosophers

std::counting_semaphore chopstick[N]; // One semaphore for each chopstick

void philosopher(int id) { while (true) { std::cout << "Philosopher " << id << " is thinking...\n"; std::this_thread::sleep_for(std::chrono::seconds(1));

    // Pick up left chopstick
    chopstick[id].acquire();

    // Pick up right chopstick
    chopstick[(id + 1) % N].acquire();

    std::cout << "Philosopher " << id << " is eating...\n";
    std::this_thread::sleep_for(std::chrono::seconds(2));

    // Put down left chopstick
    chopstick[id].release();

    // Put down right chopstick
    chopstick[(id + 1) % N].release();

    std::cout << "Philosopher " << id << " finished eating and put down chopsticks.\n";
}

}

int main() { std::vectorstd::thread threads(N);

// Initialize chopstick semaphores
for (int i = 0; i < N; i++) {
    chopstick[i] = std::counting_semaphore<N>(1);
}

// Create philosopher threads
for (int i = 0; i < N; i++) {
    threads[i] = std::thread(philosopher, i);
}

// Join threads (never ends in this example)
for (auto& th : threads) {
    if (th.joinable()) {
        th.join();
    }
}

return 0;

}

Java

import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit;

public class DiningPhilosophers { private static final int N = 5; // Number of philosophers private static final Semaphore[] chopstick = new Semaphore[N];

public static void main(String[] args) {
    // Initialize chopstick semaphores
    for (int i = 0; i < N; i++) {
        chopstick[i] = new Semaphore(1);
    }

    // Create philosopher threads
    for (int i = 0; i < N; i++) {
        new Thread(new Philosopher(i)).start();
    }
}

static class Philosopher implements Runnable {
    private final int id;

    Philosopher(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println("Philosopher " + id + " is thinking...");
            sleep(1);

            // Pick up left chopstick
            try { chopstick[id].acquire(); } catch (InterruptedException e) { e.printStackTrace(); }

            // Pick up right chopstick
            try { chopstick[(id + 1) % N].acquire(); } catch (InterruptedException e) { e.printStackTrace(); }

            System.out.println("Philosopher " + id + " is eating...");
            sleep(2);

            // Put down left chopstick
            chopstick[id].release();

            // Put down right chopstick
            chopstick[(id + 1) % N].release();

            System.out.println("Philosopher " + id + " finished eating and put down chopsticks.");
        }
    }

    private void sleep(int seconds) {
        try { TimeUnit.SECONDS.sleep(seconds); } catch (InterruptedException e) { e.printStackTrace(); }
    }
}

}

Python

import threading import time from threading import Semaphore

N = 5 # Number of philosophers chopstick = [Semaphore(1) for _ in range(N)]

def philosopher(id): while True: print(f'Philosopher {id} is thinking...') time.sleep(1)

    # Pick up left chopstick
    chopstick[id].acquire()

    # Pick up right chopstick
    chopstick[(id + 1) % N].acquire()

    print(f'Philosopher {id} is eating...')
    time.sleep(2)

    # Put down left chopstick
    chopstick[id].release()

    # Put down right chopstick
    chopstick[(id + 1) % N].release()

    print(f'Philosopher {id} finished eating and put down chopsticks.')

threads = []

Create philosopher threads

for i in range(N): thread = threading.Thread(target=philosopher, args=(i,)) threads.append(thread) thread.start()

Join threads (never ends in this example)

for thread in threads: thread.join()

`

Explanation

**1. Semaphores for chopsticks

sem_t chopstick[N];

Each chopstick is represented by a binary semaphore (1 = free, 0 = in use).

**2. Philosopher function

**3. Thread creation

**4. Circular arrangement: Right chopstick is (id+1)%N ensures philosopher 4 gets chopsticks 4 and 0.

**Problem with this code

If all philosophers pick up their left chopstick at the same time, they will all wait for the right chopstick deadlock.

Deadlock Avoidance

One common fix is to allow only **N-1 philosophers to pick chopsticks at a time. This breaks the circular wait condition.

sem_t room; // new semaphore

sem_init(&room, 0, N-1); // allow only N-1 philosophers inside

// before picking chopsticks
sem_wait(&room);

// after eating
sem_post(&room);

This ensures that at least one philosopher can always eat, preventing deadlock.