【问题标题】:fatal error: all goroutines are asleep - deadlock致命错误:所有 goroutine 都处于休眠状态 - 死锁
【发布时间】:2018-07-10 15:41:55
【问题描述】:

我有以下 Go 代码

package main

import (
    "fmt"
    "math/rand"
)

const (
    ROCK int = iota
    PAPER
    SCISSORS
)

type Choice struct {
    Who   int //0 you 1 your opponent
    Guess int
}

//Win returns true if you win.
func Win(you, he int) bool {
    ...
}

func Opponent(guess chan Choice, please chan struct{}) {
    for i := 0; i < 3; i++ {
        <-please
        choice := rand.Intn(3)
        who := 1
        guess <- Choice{who, choice}
        please <- struct{}{}
    }
}

func GetChoice(you, he int) int {
    ...
}

var Cheat func(guess chan Choice) chan Choice = func(guess chan Choice) chan Choice {
    new_guess := make(chan Choice)
    // go func() {
    for i := 0; i < 3; i++ {
        g1 := <-guess
        g2 := <-guess
        if g1.Who == 0 {
            choice := GetChoice(g1.Guess, g2.Guess)
            new_guess <- g2
            new_guess <- Choice{g1.Who, choice}
        } else {
            choice := GetChoice(g2.Guess, g1.Guess)
            new_guess <- g1
            new_guess <- Choice{g2.Who, choice}
        }
    }
    // }()
    fmt.Println("...")
    return new_guess
}

func Me(guess chan Choice, please chan struct{}) {

    for i := 0; i < 3; i++ {
        <-please
        choice := rand.Intn(3)
        who := 0
        guess <- Choice{who, choice}
        please <- struct{}{}
    }
}

func Game() []bool {
    guess := make(chan Choice)
    //please sync 2 goroutines.
    please := make(chan struct{})
    go func() { please <- struct{}{} }()
    go Opponent(guess, please)
    go Me(guess, please)
    guess = Cheat(guess)
    var wins []bool

    for i := 0; i < 3; i++ {
        g1 := <-guess
        g2 := <-guess
        win := false
        if g1.Who == 0 {
            win = Win(g1.Guess, g2.Guess)
        } else {
            win = Win(g2.Guess, g1.Guess)
        }
        wins = append(wins, win)
    }

    return wins
}

func main() {
    win := Game()
    fmt.Println(win)
}

当我运行此代码时,我收到错误致命错误:所有 goroutines 都处于睡眠状态 - 死锁!。但是,当我取消注释上面 Cheat 函数中的 go func() 行时,错误消失了。我不明白为什么在第一种情况下会出现错误,以及为什么在使用 goroutine 时会消失。那么如果有人可以解释一下吗?

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    在这个简化的例子中:

    func Cheat(guess chan Choice) chan Choice {
            new_guess := make(chan Choice)
            new_guess <- Choice{}
            <-guess
            return new_guess
    }
    

    当对新分配的通道进行写入时,其他人可能无法拥有该通道,因此写入将永远阻塞。由于写入阻塞,从guess 读取永远不会发生。但是,在您引用的代码中,Cheat() 函数是唯一从guess 通道读取的内容;所以写入它的东西会在读取发生时被阻止,直到写入 new_guess 才会发生读取,并且在包含函数返回之前不会发生写入。

    如果你将通道 I/O 移动到一个 goroutine 中,那么包含函数可以在事情进展之前返回,因此Cheat() 中的写入与Game() 末尾的读取配对并且事情可以向前推进.

    【讨论】:

      猜你喜欢
      • 2015-04-02
      • 1970-01-01
      • 2015-01-11
      • 2013-11-22
      • 1970-01-01
      • 2012-09-06
      • 2022-01-21
      • 2021-04-05
      • 1970-01-01
      相关资源
      最近更新 更多