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 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思