summaryrefslogtreecommitdiff
path: root/philo.go
diff options
context:
space:
mode:
Diffstat (limited to 'philo.go')
-rw-r--r--philo.go149
1 files changed, 40 insertions, 109 deletions
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()
}
}