douxie1894 2018-07-10 05:33
浏览 36
已采纳

致命错误:所有goroutine都处于睡眠状态-死锁

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条回答 默认 最新

  • dph23577 2018-07-10 06:56
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器