Created
March 16, 2025 05:21
-
-
Save potat-dev/f9666ebdc9171fb0e946dfd748683589 to your computer and use it in GitHub Desktop.
Dining philosophers problem in Golang
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 ( | |
"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