2016-05-11 38 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