2016-05-11 5 views
0

私はgolangプログラミングにとって非常に新しく、私はdeadlockを生成する次のプログラムを持っていますが、私はなぜそれを理解できませんか?私のgoプログラムでデッドロックが発生するのはなぜですか?

もう1つのことは、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

nil Sを受け取りますデッドロックが発生する理由は、select内のbreakselectから壊れ、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

あなたのプログラムの終了(したがって、デッドロック、そして再びループに入る)のみselectの勃発でbreakreturnと交換正常に動作します:確かにhttps://play.golang.org/p/j5bDaj3z7y

specificationsから:

"break"ステートメントは、同じ関数内の最も内側の "for"、 "switch"、または "select"ステートメントの実行を終了します。

return(私がやったように)、goto、または他のアーキテクチャのリファクタリングで回避できます。

無限ループについては、それが閉じられたチャンネルが常に返す代わりにすることを、同じ問題ですので、breakselectの外にする際に、あなたが戻ってループを入力して、永遠に閉じられたチャネルから

+1

また、 – LinearZoetrope

関連する問題