2021-06-27

Identifying golang deadlock. 5 philosophers problem

I am getting fatal error: all goroutines are asleep - deadlock! on the line wg.Wait() It happens for about ~30% of the runs, the rest are finished with no error. I guess I am not using WaitGroup the wrong way, but not sure what am I doing wrong. Maybe someone can help me identify my bug? Thanks!

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

const (
    numOfPhilosophers = 5
    numOfMeals = 3
    maxEaters = 2
)

var doOnce sync.Once

func main() {
    chopsticks := make([]sync.Mutex, 5)
    permissionChannel := make(chan bool)
    finishEating := make(chan bool)
    go permissionFromHost(permissionChannel,finishEating)
    var wg sync.WaitGroup
    wg.Add(numOfPhilosophers)
    for i:=1 ; i<=numOfPhilosophers ; i++ {
        go eat(i, chopsticks[i-1], chopsticks[i%numOfPhilosophers], &wg, permissionChannel, finishEating)
    }
    wg.Wait()
}

func eat(philosopherId int, left sync.Mutex, right sync.Mutex, wg *sync.WaitGroup, permissionChannel <-chan bool, finishEatingChannel chan<- bool) {
    defer wg.Done()
    for i:=1 ; i<=numOfMeals ; i++ {
        //lock chopsticks in random order
        if RandBool() {
            left.Lock()
            right.Lock()
        } else {
            right.Lock()
            left.Lock()
        }

        fmt.Printf("waiting for permission from host %d\n",philosopherId)
        <-permissionChannel

        fmt.Printf("starting to eat %d (time %d)\n", philosopherId, i)
        fmt.Printf("finish to eat %d (time %d)\n", philosopherId, i)
        //release chopsticks
        left.Unlock()
        right.Unlock()

        //let host know I am done eating
        finishEatingChannel<-true
    }
}

func permissionFromHost(permissionChannel chan<-bool, finishEating <-chan bool) {
    ctr := 0
    for {
        select {
        case <-finishEating:
            ctr--
        default:
            if ctr<maxEaters {
                ctr++
                permissionChannel<-true
            }
        }
    }
}

func RandBool() bool {
    rand.Seed(time.Now().UnixNano())
    return rand.Intn(2) == 1
}


from Recent Questions - Stack Overflow https://ift.tt/3A0LZbE
https://ift.tt/eA8V8J

No comments:

Post a Comment