Skip to content

Instantly share code, notes, and snippets.

@potat-dev
Created March 16, 2025 05:21
Show Gist options
  • Save potat-dev/f9666ebdc9171fb0e946dfd748683589 to your computer and use it in GitHub Desktop.
Save potat-dev/f9666ebdc9171fb0e946dfd748683589 to your computer and use it in GitHub Desktop.
Dining philosophers problem in Golang
package main
import (
"context"
"fmt"
"os"
"sync"
"time"
)
// Fork dummy struct
type Fork struct {
sync.Mutex
}
// Server dummy struct
type Server struct{}
// State enum type
type State int
const (
stateRelease State = iota - 1
stateRequest
stateHold
)
// ForkOrder enum type
type ForkOrder int
const (
forkOrderForward ForkOrder = iota
forkOrderAround
)
const (
philNum int = 5
forksNeedNum int = 2
servNum int = philNum / forksNeedNum
waitDur time.Duration = 500 * time.Millisecond
forkOrder ForkOrder = forkOrderAround
)
const (
philTag string = "Phil-"
forkTag string = "Fork-"
servTag string = "Server"
)
var (
logFile *os.File
)
func mod(a, b int) int {
return (a%b + b) % b
}
func getForwardForkID(philID int, num int) int {
return mod(philID+num, philNum)
}
func getAroundForkID(philID int, num int) int {
if num%2 == 0 {
return mod(philID+num/2, philNum)
}
return mod(philID-(num/2)-1, philNum)
}
func getForkID(philID int, num int) int {
switch forkOrder {
case forkOrderAround:
return getAroundForkID(philID, num)
case forkOrderForward:
return getForwardForkID(philID, num)
default:
return philID
}
}
func logResource(who string, what string, state State, msg string) {
var line string
switch state {
case stateRequest:
line = fmt.Sprintf("\t%s-->>%s: %s\n", who, what, msg)
case stateHold:
line = fmt.Sprintf("\t%s->>+%s: %s\n", who, what, msg)
case stateRelease:
line = fmt.Sprintf("\t%s-->>-%s: %s\n", what, who, msg)
}
fmt.Fprintf(logFile, line)
}
func logActivity(who string, active bool, msg string) {
var state, note string
if active {
state = "activate"
note = fmt.Sprintf("\tNote right of %s: %s\n", who, msg)
} else {
state = "deactivate"
}
fmt.Fprintf(logFile, "\t%s %s\n%s", state, who, note)
}
func philosopher(ctx context.Context, id int, servers chan Server, forks *[philNum]Fork, sleep time.Duration) {
philName := fmt.Sprintf("%s%d", philTag, id)
for {
select {
case <-ctx.Done():
return
default:
logResource(philName, servTag, stateRequest, "Wait For Server")
select {
case server := <-servers:
logResource(philName, servTag, stateHold, "Got Server")
for i := range forksNeedNum {
fid := getForkID(id, i)
forkName := fmt.Sprintf("%s%d", forkTag, fid)
logResource(philName, forkName, stateRequest, "Wait For Fork")
forks[fid].Lock()
logResource(philName, forkName, stateHold, "Got Fork")
}
logActivity(philName, true, "Eating")
time.Sleep(sleep)
logActivity(philName, false, "Eating")
for i := range forksNeedNum {
fid := getForkID(id, i)
forkName := fmt.Sprintf("%s%d", forkTag, fid)
forks[fid].Unlock()
logResource(philName, forkName, stateRelease, "Release Fork")
}
servers <- server
logResource(philName, servTag, stateRelease, "Release Server")
logActivity(philName, true, "Thinking")
time.Sleep(sleep)
logActivity(philName, false, "Thinking")
case <-ctx.Done():
return
}
}
}
}
func main() {
var err error
logFile, err = os.Create("flow.md")
if err != nil {
panic(err)
}
defer logFile.Close()
fmt.Fprintln(logFile, "sequenceDiagram")
fmt.Fprintf(logFile, "\tparticipant %s\n", servTag)
for id := range philNum {
fmt.Fprintf(logFile, "\tparticipant %s%d\n", philTag, id)
fmt.Fprintf(logFile, "\tparticipant %s%d\n", forkTag, id)
}
var forks [philNum]Fork
servers := make(chan Server, servNum)
for range servNum {
servers <- Server{}
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for id := range philNum {
wg.Add(1)
go func(id int) {
defer wg.Done()
philosopher(ctx, id, servers, &forks, waitDur)
}(id)
}
time.Sleep(3 * time.Second)
cancel()
wg.Wait()
fmt.Println("All philosophers have stopped")
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment