1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
package main
import (
"fmt"
"runtime"
)
type philosopher struct {
i int
forks [2]chan bool
eating chan int
done chan struct{}
}
func (p philosopher) run() {
for {
select {
case <-p.done:
return
case <-p.forks[0]:
p.eat()
}
}
}
func (p philosopher) eat() {
select {
case <-p.done:
return
case <-p.forks[1]:
p.eating <- p.i
p.forks[0] <- true
p.forks[1] <- true
runtime.Gosched()
}
}
func startPhilosophers(n int) (chan struct{}, chan int) {
philosophers := make([]*philosopher, n)
chans := make([]chan bool, n)
for i := range chans {
chans[i] = make(chan bool, 1)
chans[i] <- true
}
eating := make(chan int, n)
done := make(chan struct{})
for i := range philosophers {
var min, max int
if i == n - 1 {
min = 0
max = i
} else {
min = i
max = i + 1
}
philosophers[i] = &philosopher{i: i, forks: [2]chan bool{chans[min], chans[max]}, eating: eating, done: done}
go philosophers[i].run()
}
return done, eating
}
func wait(c chan int) {
fmt.Println(<- c)
runtime.Gosched()
}
func main() {
// Restrict go to 1 real thread so we can be sure we're seeing goroutines
// and not threads.
runtime.GOMAXPROCS(1)
// Create a bunch of goroutines
done, eating := startPhilosophers(20) // stop1
// Now turn up the number of threads so this goroutine is likely to get
// scheduled on a different thread.
runtime.GOMAXPROCS(runtime.NumCPU()) // stop2
// Now let things run. Hopefully we'll bounce around
wait(eating)
wait(eating)
wait(eating)
wait(eating)
wait(eating)
wait(eating)
wait(eating)
wait(eating)
wait(eating)
wait(eating)
close(done)
fmt.Println("done") // stop3
}
|