2016-08-08 21 views
2

sich der folgende go playgroundDeadlock wenn goroutine in einem for-Schleife Laichen

package main 

import "fmt" 

func main() { 

    var chan_array [2]chan int 

    chan1 := make(chan int) 
    chan2 := make(chan int) 

    chan_array[0] = chan1 
    chan_array[1] = chan2 


    for i := 0; i < 2; i++ { 
     go func() { 

      select { 
       case x := <- chan_array[i]: 
        if (x == 0) { 
         return 
        }  
        fmt.Println(x) 
      } 
     }() 
    } 

    chan1<- 1 
    chan2<- 2 
    chan1<- 0 
    chan2<- 0 
} 

Der obige Code versucht 2 ausgeführt goroutines zu schaffen, mit der zu dem Kanal zuhört drucken oder zu schließen, um zu signalisieren.

Aber der obige Code läuft in totes Schloss.

Ich bin nicht ganz sicher, warum

jemand meinen Fehler kann darauf hinweisen?

Dank

+0

Mögliche Duplikat [? Warum Golang Verschlüsse anders behandeln in goroutines] (http://stackoverflow.com/questions/25919213/why-does-golang-handle-closures -differently-in-goroutines) –

Antwort

4

Es gibt einige Probleme:
Was ist der Wert von i ist, wenn chan_array[i-1] läuft:

for i := 0; i < 2; i++ { 
    go func() { 
     select { 
     case x := <- chan_array[i-1]: 
      if x == 0 { 
       return 
      } 
      fmt.Println(x) 
     } 
    }() 
} 

try this:

for i := 0; i < 2; i++ { 
    go func(i int) { 
     select { 
     case x := <-chan_array[i]: 
      if x == 0 { 
       return 
      } 
      fmt.Println(x) 
     } 
    }(i) 
} 

Lassen Sie uns Ihren Code vereinfachen (mit einigen Korrekturen):

package main 

import "fmt" 

func main() { 
    chan1 := make(chan int) 
    chan2 := make(chan int) 

    go routine(chan1) 
    go routine(chan2) 

    chan1 <- 1 
    chan2 <- 2 
    chan1 <- 0 
    chan2 <- 0 
} 

func routine(ch chan int) { 
    select { 
    case x := <-ch: 
     if x == 0 { 
      return 
     } 
     fmt.Println(x) 
    } 
} 

Mit diesen:

chan1 <- 1 
chan2 <- 2 

fatalen Fehler:

all goroutines are asleep - deadlock! 

Ihre goroutines fertig und keine goroutines hören-chan1 und chan1 hier:

chan1 <- 0 
chan2 <- 0 

Ihre korrigierten Arbeitscodebeispiel ist :

package main 

import "fmt" 

func main() { 
    chan1 := make(chan int) 
    chan2 := make(chan int) 

    go routine(chan1) 
    go routine(chan2) 

    chan1 <- 1 
    chan2 <- 2 
    chan1 <- 0 
    chan2 <- 0 
} 

func routine(ch chan int) { 
    for { 
     select { 
     case x := <-ch: 
      if x == 0 { 
       return 
      } 
      fmt.Println(x) 
     } 
    } 
} 

Ausgang:

1 
2 
1

Mit der Zeit werden die goroutines die Variable i hat läuft bereits erhöht. Übergeben Sie es stattdessen als Funktionsparameter.

In der Tat, verlassen Sie sich nie auf Variablen aus einer Funktion Schließung in goroutines. Es ist zu unzuverlässig.

+0

Ich habe versucht, den Parameter hinzuzufügen, aber ich habe [dead lock] (https://play.golang.org/p/SxcnORT6Ru). – user3591466

+0

@ user3591466: Nun, es gibt ein anderes Problem. Du sendest zweimal zu den Kanälen, aber deine Göroutinen verlassen nach Erhalt eines Wertes. –