summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--forks.go33
-rw-r--r--main.go41
-rw-r--r--names.go21
-rw-r--r--philo.go149
4 files changed, 135 insertions, 109 deletions
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()
}
}