DEV Community

Tabrez Ahmed
Tabrez Ahmed

Posted on

Concurrency in Python: Solving the Dining Philosophers Problem

If you are writing multithreaded applications, you are going to run into deadlocks. There’s no avoiding it. To understand how to fix them, you need to understand the Dining Philosophers problem.

Five philosophers sit at a round table. There are five forks. To eat, a philosopher needs the fork on their left and the fork on their right. If everyone grabs their left fork at the exact same time, they all wait forever for the right fork. Deadlock.

In this series, my team and I will break down how we built a visual simulator for this problem in Python. For part one, we are looking at the core mechanics and Dijkstra’s Resource Hierarchy solution.
The Setup

We want raw execution without third-party bloat, so we rely entirely on Python's standard threading library. Each philosopher is a daemon thread, and each fork is a threading.Lock.
Python

import threading

NUM_PHILOSOPHERS = 5
forks = [threading.Lock() for _ in range(NUM_PHILOSOPHERS)]
Enter fullscreen mode Exit fullscreen mode

If we just wrote forks[left].acquire() followed by forks[right].acquire(), the script would eventually freeze.
The Solution: Resource Hierarchy

To break the circular wait, we assign a hierarchy to the resources (forks). Instead of "grab left, then right," the rule becomes "grab the lower-numbered fork first, then the higher-numbered one."

Here is how that logic looks in our simulation loop:
Python

def _cycle_resource_hierarchy(self, idx: int):
    # Determine fork indices
    left  = (idx - 1) % NUM_PHILOSOPHERS
    right = idx

    # Establish hierarchy
    lo, hi = min(left, right), max(left, right)

    # Acquire in strict order
    self.forks[lo].acquire()
    self.forks[hi].acquire()

    # CRITICAL SECTION: Eating
    time.sleep(random.uniform(0.4, 1.5))

    # Release locks
    self.forks[hi].release()
    self.forks[lo].release()
Enter fullscreen mode Exit fullscreen mode

Because the last philosopher (index 4) sits next to the first fork (index 0), they will try to grab fork 0 first, while philosopher 0 is also trying to grab fork 0 first. The cycle is broken. Someone gets blocked, allowing someone else to eat.

Top comments (0)