猿问

识别戈兰死锁。5 哲学家问题

我正在排队 大约30%的运行都会发生这种情况,其余的都完成了,没有错误。我想我使用WaitGroup的方式是错误的,但不确定我做错了什么。也许有人可以帮助我识别我的错误?谢谢!fatal error: all goroutines are asleep - deadlock!wg.Wait()


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

}

编辑1:我修复了通过引用传递的互斥体。它没有解决问题。


编辑2:我试图使用缓冲通道,使其工作permissionChannel:=make(chan bool, numOfPhilosophers)


编辑3:也@Jaroslaw例子使它工作


跃然一笑
浏览 153回答 2
2回答

蛊毒传说

最后一个 goroutine 不会退出,当它写入通道时,它将在最后一次迭代中被阻止,因为它没有消费者。没有消费者的原因是函数中的选择情况正在写入,但没有消费者,因为它正在等待它被读取,所以我们有一个死锁。finishEatingChannelfinishEatingChannelpermissionFromHostpermissionChannel<-truepermissionChannel您可以使权限从主机通道缓冲,它将解决此问题。您的代码中还有一个错误,您正在按值传递互斥体,这是不允许的

慕后森

该命令说go vet./main.go:26:13: call of eat copies lock value: sync.Mutex./main.go:26:30: call of eat copies lock value: sync.Mutex./main.go:31:34: eat passes lock by value: sync.Mutex./main.go:31:52: eat passes lock by value: sync.Mutex另一个问题是,有时 goroutines(哲学家)在尝试发送确认时会被阻止,因为负责从此无缓冲通道读取数据的 goroutine(主机)正忙于尝试发送权限。以下是代码的确切部分:finishEatingChannel&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ctr<maxEaters {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctr++&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // This goroutine stucks since the last philosopher is not reading from permissionChannel.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Philosopher is not reading from this channel at is busy trying to write finishEating channel which is not read by this goroutine.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Thus the deadlock happens.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; permissionChannel<-true&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }死锁是100%可重复的,当只剩下一个哲学家需要吃两次饭时。固定版本的代码:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "math/rand"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")const (&nbsp; &nbsp; numOfPhilosophers = 5&nbsp; &nbsp; numOfMeals&nbsp; &nbsp; &nbsp; &nbsp; = 3&nbsp; &nbsp; maxEaters&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 2)func main() {&nbsp; &nbsp; chopsticks := make([]sync.Mutex, 5)&nbsp; &nbsp; permissionChannel := make(chan bool)&nbsp; &nbsp; finishEating := make(chan bool)&nbsp; &nbsp; go permissionFromHost(permissionChannel, finishEating)&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; wg.Add(numOfPhilosophers)&nbsp; &nbsp; for i := 1; i <= numOfPhilosophers; i++ {&nbsp; &nbsp; &nbsp; &nbsp; go eat(i, &chopsticks[i-1], &chopsticks[i%numOfPhilosophers], &wg, permissionChannel, finishEating)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()}func eat(philosopherId int, left *sync.Mutex, right *sync.Mutex, wg *sync.WaitGroup, permissionChannel <-chan bool, finishEatingChannel chan<- bool) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; for i := 1; i <= numOfMeals; i++ {&nbsp; &nbsp; &nbsp; &nbsp; //lock chopsticks in random order&nbsp; &nbsp; &nbsp; &nbsp; if RandBool() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left.Lock()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right.Lock()&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; right.Lock()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; left.Lock()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("waiting for permission from host %d\n", philosopherId)&nbsp; &nbsp; &nbsp; &nbsp; <-permissionChannel&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("starting to eat %d (time %d)\n", philosopherId, i)&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("finish to eat %d (time %d)\n", philosopherId, i)&nbsp; &nbsp; &nbsp; &nbsp; //release chopsticks&nbsp; &nbsp; &nbsp; &nbsp; left.Unlock()&nbsp; &nbsp; &nbsp; &nbsp; right.Unlock()&nbsp; &nbsp; &nbsp; &nbsp; //let host know I am done eating&nbsp; &nbsp; &nbsp; &nbsp; finishEatingChannel <- true&nbsp; &nbsp; }}func permissionFromHost(permissionChannel chan<- bool, finishEating <-chan bool) {&nbsp; &nbsp; ctr := 0&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; if ctr < maxEaters {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-finishEating:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctr--&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case permissionChannel <- true:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctr++&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <-finishEating&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctr--&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func RandBool() bool {&nbsp; &nbsp; rand.Seed(time.Now().UnixNano())&nbsp; &nbsp; return rand.Intn(2) == 1}
随时随地看视频慕课网APP

相关分类

Go
我要回答