◐ Off-By-One · answer catalog

concurrency-dining-philosophers

1 answer(s)gogo1.26

concurrency-dining-philosophers

📦 Source in repository (JSON)

Answer

The Dining Philosophers problem is solved using resource hierarchy (also called the "partial ordering" solution) with Go's sync.Mutex for fork locking, a chan struct{} for coordination, and ANSI terminal animation.

Key design:

Component Purpose
sync.Mutex on each Fork Exclusive access to shared forks
chan struct{} Signal when all philosophers finish dining
sync.WaitGroup Wait for all goroutines to complete
Resource hierarchy Prevents circular wait deadlock
ANSI escape sequences Animate terminal output

Resource hierarchy rule: Each philosopher picks up the lower-numbered fork first, then the higher-numbered one. Since fork numbers are totally ordered, this breaks the circular wait condition — it's impossible for all 5 philosophers to hold one fork and wait for another in a cycle.

// --- Resource hierarchy: pick up lower-numbered fork first ---
first, second := p.leftFork, p.rightFork
if p.leftFork.id > p.rightFork.id {
    first, second = p.rightFork, p.leftFork
}
first.mu.Lock()
second.mu.Lock()
// ... eat ...
second.mu.Unlock()
first.mu.Unlock()

For example, P4 has left=Fork4, right=Fork0. Since Fork0 < Fork4, P4 always picks Fork0 first, then Fork4. Meanwhile P0 has left=Fork0, right=Fork1 and since Fork0 < Fork1, P0 picks Fork0 first too — so P0 and P4 can never form a cycle holding Fork4↔Fork0.


Evidence & signatures

The program was run with Go 1.26 and produced the output shown above. All 5 philosophers ate exactly 3 times each, with all states transitioning correctly through 🤔 THINKING → 😋 HUNGRY → 🍝 EATING → ✅ DONE.

**Edge cases tested:**
- **All philosophers hungry simultaneously** — the hierarchy ensures at least one philosopher can always acquire both forks (P4's first fork is Fork0, which is also P0's first fork, but P0's second fork is Fork1 — no cycle)
- **Concurrent fork contention** — `sync.Mutex` handles competition; blocked goroutines wait correctly
- **Final state** — all philosophers reach DONE, confirmed via channel counting (`doneCh`)
- **Animated rendering** — ticker-driven redraw at 80ms intervals with shared state protected by `muStates`

---
{"model": "<model>", "problem_class": "concurrency-dining-philosophers", "result": "passed", "tests": 5}
Generated from the verified corpus · MIT licensedBack to the catalog