2016-08-16 3 views
1

私はチャネルに書き込んでいる関数(クロージャではない)を持っています。私は今、私は別のゴルーチンを使用して、そのチャンネルから読み取るしようとしていますgoroutineとエラーを与えるクロージャを使用したチャネル経由での同時関数の読み込み

for ; ; { 

    if err == io.EOF { 
     fmt.Println(err) 
     close(somechan) 
     fmt.Println("Closed channel") 
     break 
    } else if err != nil { 
     panic(err) 
    } 
    somechan <- Somefunc() 
} 

のようなものを持って、

var wg sync.WaitGroup 
wg.Add(1) 
go DoStuff(somechan, &wg) 

インサイドDoStuffとしてゴルーチンから、その関数を呼び出しています。

実行している場合しかし、私はwgread.Addを与えた場合(2)、それは上記のDONEと3偽を出力します

DONE 
false 
DONE 
false 

を印刷した後

panic: sync: negative WaitGroup counter 

を取得しています

wgread.Add(1) 
go func() { 
    for ; ; { 
     select { 
     case chanoutput, ok := <-somechan: 
      if ok == true { 
       fmt.Println(string(*chanoutput)) 
      } else { 
       fmt.Println("DONE") 
       fmt.Println(ok) 
       wgread.Done() 
       break 
      } 
     } 

    } 
}() 
wgread.Wait() 

回。

私はウェイトグループデルタを1だけインクリメントしても、なぜマイナスのウェイトグループカウンタエラーを出すのですか?別の同時関数またはクロージャを使用して、ゴルーチンから読み込む最良の方法は何ですか?

+0

ここに問題を伝えるのに十分なコードがありません。 –

答えて

3

breakステートメントは、forまたはswitchステートメントの最も内側のケースからブレークアウトします。 somechanで受信する関数は、チャネルが終了したときに待機グループを減分するループ内でスピンします。

wgread.Add(1) 
go func() { 
    defer wgread.Done() 
    for chanoutput := range somechan { 
     fmt.Println(string(*chanoutput)) 
    } 
    fmt.Println("DONE") 
}() 
wgread.Wait() 

受信コードがこの質問に書かれている場合は、受信側のゴルーチンを削除することができます。コードをwgread.Add(1)からwgread.Wait()に置き換えて

for chanoutput := range somechan { 
    fmt.Println(string(*chanoutput)) 
} 
3

breakは、ループを外しません。forループです。外側のループを参照するために 、あなたはこのようにラベルを使用することができます:あなたのコードをフォーマットするgofmtを使って練習してください コーディングスタイル、を支援するためにも

Loop: 
    for { 
     select { 
      case ...: 
       break Loop 
     } 
    } 

。たとえば、for ; ; { ... }をクリーナーfor { ... }に置き換えます。

+0

@Balooありがとうございますが、ブレークループでは、メインスレッドは今待っています。 – scott

関連する問題