Skip to content

Instantly share code, notes, and snippets.

@1player
Created June 27, 2013 18:31
Show Gist options
  • Save 1player/5879083 to your computer and use it in GitHub Desktop.
Save 1player/5879083 to your computer and use it in GitHub Desktop.
Playing with the Dining Philosophers problem and Go..
package main
import (
"fmt"
"os"
"os/signal"
"time"
)
const n = 5
const eatingTime = 2
const thinkingTime = 1
const workTime = eatingTime + thinkingTime
const patience = 2000
type Fork struct {
}
type Philosopher struct {
id int
index int
eaten int
leftHand *Fork
rightHand *Fork
leftHolder chan *Fork
rightHolder chan *Fork
table *Table
overheadAvg float64
}
type Table struct {
seats []*Philosopher
forkHolder []chan *Fork
}
func (p *Philosopher) Think() {
fmt.Println("Philosopher", p.id, "is thinking...")
time.Sleep(thinkingTime * time.Second)
}
func (p *Philosopher) GetForks() chan bool {
ready := make(chan bool)
go func() {
for p.leftHand == nil || p.rightHand == nil {
p.leftHand = <-p.leftHolder
fmt.Println("Philosopher", p.id, "has picked up the left fork.")
p.rightHand = <-p.rightHolder
fmt.Println("Philosopher", p.id, "has picked up the right fork.")
}
ready <- true
}()
return ready
}
func (p *Philosopher) PutForks() {
if p.leftHand != nil {
p.leftHolder <- p.leftHand
fmt.Println("Philosopher", p.id, "has put down the left fork.")
p.leftHand = nil
}
if p.rightHand != nil {
p.rightHolder <- p.rightHand
fmt.Println("Philosopher", p.id, "has put down the right fork.")
p.rightHand = nil
}
}
func (p *Philosopher) Eat() {
for {
select {
case <-p.GetForks():
fmt.Println("Philosopher", p.id, "is dining.")
time.Sleep(eatingTime * time.Second)
fmt.Println("Philosopher", p.id, "has finished.")
p.eaten++
p.PutForks()
return
case <-time.After(patience * time.Millisecond):
p.PutForks()
time.Sleep(500 * time.Millisecond)
}
}
}
func (p *Philosopher) Loop() {
for {
start := time.Now()
p.Think()
p.Eat()
totalTime := time.Now().Sub(start)
overhead := totalTime - (workTime * time.Second)
overheadPerc := 100.0 * (float64(overhead) / float64(totalTime))
p.overheadAvg = (overheadPerc + float64(p.eaten-1)*p.overheadAvg) / float64(p.eaten)
fmt.Println("Philosopher", p.id, "overhead% ", overheadPerc, "total", totalTime)
}
}
func spawn(index int, table *Table) *Philosopher {
p := &Philosopher{
id: index + 1,
index: index,
table: table,
}
p.leftHolder = table.forkHolder[p.index]
if index == n-1 {
p.rightHolder = table.forkHolder[0]
} else {
p.rightHolder = table.forkHolder[index+1]
}
fmt.Println(p)
go p.Loop()
return p
}
func main() {
table := &Table{
seats: make([]*Philosopher, n),
forkHolder: make([]chan *Fork, n),
}
for i := 0; i < n; i++ {
table.forkHolder[i] = make(chan *Fork, 1)
}
for i := 0; i < n; i++ {
table.seats[i] = spawn(i, table)
}
for i := 0; i < n; i++ {
table.forkHolder[i] <- &Fork{}
}
ctrlc := make(chan os.Signal, 1)
signal.Notify(ctrlc, os.Interrupt, os.Kill)
select {
case <-ctrlc:
fmt.Println("Bye!")
for _, p := range table.seats {
fmt.Println("Philosopher", p.id, "has eaten", p.eaten, "times (avg ", p.overheadAvg, ").")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment