fatal error: all goroutines are asleep - deadlock

拟墨画扇 提交于 2019-12-13 03:55:16

问题


I've the following Go code

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)
}

When I run this code I get the error fatal error: all goroutines are asleep - deadlock!. But when I uncomment the go func() line in Cheat function above the error disappear. I couldn't understand why the error appears in the first case and why it disappears when using goroutine. So if someone could please explain this?


回答1:


In this simplified example:

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

When the write to the newly allocated channel happens, nobody else can possibly have the channel yet and so that write will block forever. Since that write blocks, the read from guess never happens. But, in the code you quoted, the Cheat() function is the only thing that reads from the guess channel; so the things that are writing to it are blocked on that read happening, that read won't happen until the write to new_guess happens, and that write can't happen until the containing function returns.

If you move the channel I/O into a goroutine, then the containing function can return before things progress, and so the write in Cheat() gets paired with the reads at the end of Game() and things can move forward.



来源:https://stackoverflow.com/questions/51257837/fatal-error-all-goroutines-are-asleep-deadlock

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!