douxie1894 2018-07-10 05:33

# 致命错误：所有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++ {
choice := rand.Intn(3)
who := 1
guess <- Choice{who, choice}
}
}

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++ {
choice := rand.Intn(3)
who := 0
guess <- Choice{who, choice}
}
}

func Game() []bool {
guess := make(chan Choice)
go func() { please <- struct{}{} }()
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 在获取boss直聘的聊天的时候只能获取到前40条聊天数据
• ¥20 关于URL获取的参数，无法执行二选一查询
• ¥15 液位控制，当液位超过高限时常开触点59闭合，直到液位低于低限时，断开
• ¥15 marlin编译错误，如何解决？
• ¥15 有偿四位数，节约算法和扫描算法
• ¥15 VUE项目怎么运行，系统打不开
• ¥50 pointpillars等目标检测算法怎么融合注意力机制
• ¥20 Vs code Mac系统 PHP Debug调试环境配置
• ¥60 大一项目课，微信小程序