Last active
March 7, 2017 04:23
-
-
Save caelifer/7f3764756f11e5e3cec5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math/rand" | |
"time" | |
) | |
type Fork struct{} | |
type Thinker struct { | |
Name string | |
Forks [2]chan *Fork | |
} | |
func (t Thinker) Start() { | |
go func() { | |
for { | |
t.Think() | |
t.Eat() | |
} | |
}() | |
} | |
func (t Thinker) Think() { | |
fmt.Printf("thinker %s is thinking...\n", t.Name) | |
time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) | |
} | |
func (t Thinker) Eat() { | |
fmt.Printf("thinker %s is ready to eat...\n", t.Name) | |
var left, right *Fork | |
var ok bool | |
for { | |
forkIdxLeft := rand.Intn(2) | |
forkIdxRight := (forkIdxLeft + 1) % 2 | |
// Get first fork | |
if left, ok = t.GetFork(forkIdxLeft); ok { | |
// Get second fork | |
if right, ok = t.GetFork(forkIdxRight); ok { | |
fmt.Printf("thinker %s is eating!\n", t.Name) | |
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) | |
// Put both forks back | |
t.Forks[0] <- left | |
t.Forks[1] <- right | |
fmt.Printf("thinker %s finished eating\n", t.Name) | |
break // Exit loop here | |
} else { | |
// Put first fork back and complain | |
fmt.Printf("thinker %s putting the fork back because the other is not available\n", t.Name) | |
t.Forks[forkIdxLeft] <- left | |
} | |
} | |
fmt.Printf("thinker %s is hungerly awaiting for the forks...\n", t.Name) | |
time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) | |
} | |
} | |
func (t Thinker) GetFork(idx int) (*Fork, bool) { | |
side := "right" | |
if idx&0x1 == 0 { | |
side = "left" | |
} | |
fmt.Printf("thinker %s is reaching for the %s fork\n", t.Name, side) | |
var fork *Fork | |
select { | |
case fork = <-t.Forks[idx]: | |
default: | |
fmt.Printf("thinker %s is blocked\n", t.Name) | |
return nil, false | |
} | |
return fork, true | |
} | |
var thinkers = []Thinker{ | |
{Name: "#1"}, | |
{Name: "#2"}, | |
{Name: "#3"}, | |
} | |
func init() { | |
// Seed our random generator | |
rand.Seed(time.Now().Unix()) | |
// Give thinkers forks | |
n := len(thinkers) | |
for i := 0; i < n; i++ { | |
thinkers[i].Forks[0] = addFork() | |
if i > 0 { | |
thinkers[i].Forks[1] = thinkers[i-1].Forks[0] | |
} | |
} | |
thinkers[0].Forks[1] = thinkers[n-1].Forks[0] // Last fork goes between first and nth thinkers | |
// Animate them | |
for _, t := range thinkers { | |
t.Start() | |
} | |
} | |
func addFork() chan *Fork { | |
f := make(chan *Fork, 1) | |
f <- &Fork{} | |
return f | |
} | |
func main() { | |
time.Sleep(2 * time.Second) | |
fmt.Println("Exiting simulation") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Live code - https://play.golang.org/p/Nz2bDvNmHG
Output: