2016-05-11 40 views
0

我对golang编程非常新,我有以下程序产生deadlock,我不明白为什么?为什么我的go程序会出现死锁?

另一件事是,如果我关闭doAdd方法的频道,然后我进入一个无限循环,这对我来说也有点奇怪。

这是程序。

var wg sync.WaitGroup 

func main() { 

    ch1 := make(chan string) 
    ch2 := make(chan string) 
    ch3 := make(chan string) 
    chClose := make(chan bool) 
    wg.Add(3) 
    go doAdd(ch1, "ch1") 
    go doAdd(ch2, "ch2") 
    go doAdd(ch3, "ch3") 

    go waitForClose(chClose) 

    for { 
     select { 
     case x := <-ch1: 
      fmt.Println("Got from ch1 ", x) 
     case y := <-ch2: 
      fmt.Println("Got from ch2 ", y) 
     case z := <-ch3: 
      fmt.Println("Got from ch3 ", z) 
     case <-chClose: 
      fmt.Println("CLOSED") 
      break 
     } 
    } 
} 

func waitForClose(chClose chan bool) { 
    wg.Wait() 
    chClose <- true 
} 

func doAdd(ch chan string, name string) { 
    for i := 0; i < 10; i++ { 
     ch <- strconv.Itoa(i) 
    } 
    wg.Done() 
} 

,输出是:

Got from ch1 0 
Got from ch1 1 
Got from ch1 2 
Got from ch1 3 
Got from ch1 4 
Got from ch1 5 
Got from ch1 6 
Got from ch1 7 
Got from ch1 8 
Got from ch1 9 
Got from ch2 0 
Got from ch2 1 
Got from ch2 2 
Got from ch2 3 
Got from ch2 4 
Got from ch2 5 
Got from ch2 6 
Got from ch2 7 
Got from ch2 8 
Got from ch2 9 
Got from ch3 0 
Got from ch3 1 
Got from ch3 2 
Got from ch3 3 
Got from ch3 4 
Got from ch3 5 
Got from ch3 6 
Got from ch3 7 
Got from ch3 8 
Got from ch3 9 
CLOSED 
fatal error: all goroutines are asleep - deadlock! 

goroutine 1 [select]: 
main.main() 
     c:/PraveenData/demo/go-work/main.go:29 +0x915 
exit status 2 

回答

2

你会得到一个僵局的原因是你selectbreak只爆发了select,留下for无环路重新进入选择,其中没有通道已经准备好要读取。

你可以通过做一些像拯救这样的:

done := false 

for !done { 
     select { 
       ... 
     case <-chClose: 
       done = true 
       fmt.Println("CLOSED") 
     } 
} 

这平凡允许for循环终止。

另一个是使用一个标签:

OuterLoop: 
     for { 
       select { 
       ... 
       case <-chClose: 
         fmt.Println("CLOSED") 
         break OuterLoop 
       } 
     } 

我个人而言,对在这种情况下,第一个版本略有偏好,但这仅仅是口味的问题。

1

break在程序结束只爆发了select的(并再次进入循环,因此死锁):用return替换它正常工作:https://play.golang.org/p/j5bDaj3z7y

事实上,从specifications

“break”语句终止同一个函数中最内层的“for”,“switch”或“select”语句的执行。

你可以通过return(如我所做的),goto或其他一些架构重构来解决这个问题。

至于无限循环,这是同样的问题,而不是封闭的通道总是返回,所以当break荷兰国际集团走出select的,你进入回圈,并从封闭的渠道获得nil永远的

+1

另外一个标签打破 – LinearZoetrope