From 6571642c66bfcef49a1cc18b950b09f13131dd5a Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 26 Feb 2017 00:00:50 +0100 Subject: Split files --- forks.go | 33 ++++++++++++++ main.go | 41 ++++++++++++++++++ names.go | 21 +++++++++ philo.go | 149 +++++++++++++++++---------------------------------------------- 4 files changed, 135 insertions(+), 109 deletions(-) create mode 100644 forks.go create mode 100644 main.go create mode 100644 names.go diff --git a/forks.go b/forks.go new file mode 100644 index 0000000..ba57ef7 --- /dev/null +++ b/forks.go @@ -0,0 +1,33 @@ +package main + +import "time" + +type Fork chan struct{} + +func NewForks(n int) []Fork { + forks := make([]Fork, n) + + for i := range forks { + forks[i] = make(Fork, 1) + forks[i].Put() + } + + return forks +} + +func (f Fork) Grab() { + <-f +} + +func (f Fork) TryGrab(d time.Duration) bool { + select { + case <-f: + return true + case <-time.After(d): + return false + } +} + +func (f Fork) Put() { + f <- struct{}{} +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..23275d1 --- /dev/null +++ b/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "math/rand" + "sync" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func main() { + names := Names{"Aristotle", "Kant", "Spinoza", "Marx", "Russell"} + flag.Var(&names, "names", "philospher names") + bites := flag.Int("bites", 3, "number of rounds") + delay := flag.Duration("max delay", 3*time.Second, "delay") + timeOut := flag.Duration("timeout", time.Second, "delay") + flag.Parse() + + forks := NewForks(len(names)) + + wg := sync.WaitGroup{} + for i, name := range names { + wg.Add(1) + p := &Philo{ + Name: name, + Left: forks[i], + Right: forks[(i+1)%len(names)], + Bites: *bites, + MaxDelay: *delay, + TimeOut: *timeOut, + } + go func() { + p.Dine() + wg.Done() + }() + } + wg.Wait() +} diff --git a/names.go b/names.go new file mode 100644 index 0000000..56a0a68 --- /dev/null +++ b/names.go @@ -0,0 +1,21 @@ +package main + +import ( + "errors" + "fmt" + "strings" +) + +type Names []string + +func (n Names) String() string { + return fmt.Sprint(strings.Join(n, ",")) +} + +func (n *Names) Set(s string) error { + *n = Names(strings.Split(s, ",")) + if len(*n) < 2 { + return errors.New("at least 2 names are required") + } + return nil +} diff --git a/philo.go b/philo.go index 030195c..056e7aa 100644 --- a/philo.go +++ b/philo.go @@ -1,154 +1,85 @@ package main import ( - "errors" - "flag" "fmt" "math/rand" - "strings" - "sync" "time" ) -type Fork struct{} - type Philo struct { - Name string - LHS chan Fork - RHS chan Fork - Bites int - Delay time.Duration - TimeOut time.Duration + Name string + Left Fork + Right Fork + Bites int + MaxDelay time.Duration + TimeOut time.Duration } -func (p Philo) rndDelay() { - n := rand.Intn(int(p.Delay)) +func (p Philo) Delay() { + n := rand.Intn(int(p.MaxDelay)) time.Sleep(time.Duration(n)) } -func (p Philo) printState(s string) { +func (p Philo) Print(s string) { fmt.Printf("%10s %s\n", p.Name, s) } -type stateFn func() stateFn - -func (p *Philo) arrive() stateFn { - p.printState("arrives") +func (p *Philo) Arrive() stateFn { + p.Print("arrives") - return p.hungry + return p.Hungry } -func (p *Philo) hungry() stateFn { - p.printState("is hungry") +func (p *Philo) Hungry() stateFn { + p.Print("is hungry") - <-p.LHS // grab left fork - - select { - case <-p.RHS: // try to grab right fork - return p.eat - case <-time.After(p.TimeOut): - p.LHS <- Fork{} // put left fork back - return p.starve + p.Left.Grab() + if ok := p.Right.TryGrab(p.TimeOut); ok { + return p.Eat } + p.Left.Put() - return p.eat + return p.Starve } -func (p *Philo) starve() stateFn { - p.printState("is starving") - p.rndDelay() +func (p *Philo) Starve() stateFn { + p.Print("is starving") + p.Delay() - return p.hungry + return p.Hungry } -func (p *Philo) eat() stateFn { - p.printState("is eating") - p.rndDelay() +func (p *Philo) Eat() stateFn { + p.Print("is eating") + p.Delay() - p.LHS <- Fork{} // release left fork - p.RHS <- Fork{} // release right fork + p.Left.Put() + p.Right.Put() if p.Bites--; p.Bites <= 0 { - return p.leave + return p.Leave } - return p.think -} - -func (p *Philo) think() stateFn { - p.printState("is thinking") - p.rndDelay() - - return p.hungry -} - -func (p *Philo) leave() stateFn { - p.printState("leaves") - - return nil + return p.Think } -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 - } +func (p *Philo) Think() stateFn { + p.Print("is thinking") + p.Delay() - return forks + return p.Hungry } -type Names []string - -func (n Names) String() string { - return fmt.Sprint(strings.Join(n, ",")) -} +func (p *Philo) Leave() stateFn { + p.Print("leaves") -func (n *Names) Set(s string) error { - *n = Names(strings.Split(s, ",")) - if len(*n) < 2 { - return errors.New("at least 2 names are required") - } return nil } -func main() { - names := Names{"Aristotle", "Kant", "Spinoza", "Marx", "Russell"} - bites := flag.Int("bites", 3, "number of rounds") - delay := flag.Duration("max delay", 3*time.Second, "delay") - timeOut := flag.Duration("timeout", time.Second, "delay") - flag.Var(&names, "names", "philospher names") - flag.Parse() - - rand.Seed(time.Now().UnixNano()) - - fmt.Println(len(names), "philosophers dining") - defer fmt.Println("Table is empty") - - forks := prepare(len(names)) - - wg := sync.WaitGroup{} - defer wg.Wait() - - for i, name := range names { - wg.Add(1) - - p := &Philo{ - Name: name, - LHS: forks[i], - RHS: forks[(i+1)%len(names)], - Bites: *bites, - Delay: *delay, - TimeOut: *timeOut, - } - - go func(p *Philo) { - defer wg.Done() +type stateFn func() stateFn - for state := p.arrive; state != nil; { - state = state() - } - }(p) +func (p *Philo) Dine() { + for state := p.Arrive; state != nil; { + state = state() } } -- cgit v1.2.3