package main import ( "fmt" "math/rand" "sync" "time" ) const ( bites = 3 delay = 3 ) var philo = []string{ "Aristotle", "Kant", "Spinoza", "Marx", "Russell", } type Fork struct{} type Philo struct { Name string LHS chan Fork RHS chan Fork Bites int } func rndDelay() { n := time.Duration(rand.Intn(delay) + 1) time.Sleep(n * time.Second) } func (p Philo) state(s string) { fmt.Printf("%10s %s\n", p.Name, s) } type stateFn func(*Philo) stateFn func arrive(p *Philo) stateFn { p.state("arrives") return hungry } func hungry(p *Philo) stateFn { p.state("is hungry") <-p.LHS // grab left fork select { case <-p.RHS: // try to grab right fork return eat case <-time.After(time.Second): p.LHS <- Fork{} // put left fork back return starve } return eat } func starve(p *Philo) stateFn { p.state("is starving") rndDelay() return hungry } func eat(p *Philo) stateFn { p.state("is eating") rndDelay() p.LHS <- Fork{} // release left fork p.RHS <- Fork{} // release right fork if p.Bites -= 1; p.Bites <= 0 { return leave } return think } func think(p *Philo) stateFn { p.state("is thinking") rndDelay() return hungry } func leave(p *Philo) stateFn { p.state("leaves") return nil } func prepare(n int) []chan Fork { forks := make([]chan Fork, n) for i := range forks { forks[i] = make(chan Fork, 1) forks[i] <- Fork{} // put a fork } return forks } func init() { rand.Seed(time.Now().UnixNano()) } func main() { fmt.Println(len(philo), "philosophers dining") defer fmt.Println("Table is empty") forks := prepare(len(philo)) wg := sync.WaitGroup{} defer wg.Wait() for i, name := range philo { wg.Add(1) p := &Philo{ Name: name, LHS: forks[i], RHS: forks[(i+1)%len(philo)], Bites: bites, } go func(p *Philo) { defer wg.Done() for state := arrive; state != nil; { state = state(p) } }(p) } }