Dining Philosophers

Dijkstra's solution: always lock the lower-numbered fork first to prevent deadlock.

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

type Philosopher struct {
	name      string
	leftFork  int
	rightFork int
}

func (p Philosopher) dine(forks map[int]*sync.Mutex, wg *sync.WaitGroup) {
	defer wg.Done()

	first, second := p.leftFork, p.rightFork
	if first > second {
		first, second = second, first
	}

	for i := 0; i < 3; i++ {
		fmt.Printf("%s is thinking\n", p.name)
		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) // simulate thinking

		forks[first].Lock()
		forks[second].Lock()

		fmt.Printf("%s is eating (round %d)\n", p.name, i+1)
		time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) // simulate eating

		forks[second].Unlock()
		forks[first].Unlock()
	}

	fmt.Printf("%s is done\n", p.name)
}

func main() {
	forks := make(map[int]*sync.Mutex)
	for i := 0; i < 5; i++ {
		forks[i] = &sync.Mutex{}
	}

	philosophers := []Philosopher{
		{"Plato", 4, 0},
		{"Socrates", 0, 1},
		{"Aristotle", 1, 2},
		{"Pascal", 2, 3},
		{"Locke", 3, 4},
	}

	var wg sync.WaitGroup
	for _, p := range philosophers {
		wg.Add(1)
		go p.dine(forks, &wg)
	}

	wg.Wait()
	fmt.Println("everyone finished")
}
▶ Open Go Playground

Copy the code above and paste to run

© 2026 ByteLearn.dev. Free courses for developers. · Privacy