私の要件の1つとして、N個のworker goルーチンを作成する必要があります。これは、1つの監視ルーチンによって監視されます。監視ルーチンは、すべてのワーカールーチンが完了したときに終了する必要があります。デッドロックで終わる私のコード、助けてください。
import "fmt"
import "sync"
import "strconv"
func worker(wg *sync.WaitGroup, cs chan string, i int ){
defer wg.Done()
cs<-"worker"+strconv.Itoa(i)
}
func monitorWorker(wg *sync.WaitGroup, cs chan string) {
defer wg.Done()
for i:= range cs {
fmt.Println(i)
}
}
func main() {
wg := &sync.WaitGroup{}
cs := make(chan string)
for i:=0;i<10;i++{
wg.Add(1)
go worker(wg,cs,i)
}
wg.Add(1)
go monitorWorker(wg,cs)
wg.Wait()
}
あなたのmonitorWorkerは決して死ぬことはありません。すべてのワーカーが終了すると、csを待機し続けます。これは、他にcsで送信されないため、wgが0に到達しないため、デッドロックになります。考えられる修正は、すべてのワーカーが終了したときにモニターにチャネルを閉じさせることです。 forループがメインにある場合、ループを終了し、メインから戻り、プログラムを終了します。
例: http://play.golang.org/p/nai7XtTMfr
package main
import (
"fmt"
"strconv"
"sync"
)
func worker(wg *sync.WaitGroup, cs chan string, i int) {
defer wg.Done()
cs <- "worker" + strconv.Itoa(i)
}
func monitorWorker(wg *sync.WaitGroup, cs chan string) {
wg.Wait()
close(cs)
}
func main() {
wg := &sync.WaitGroup{}
cs := make(chan string)
for i := 0; i < 10; i++ {
wg.Add(1)
go worker(wg, cs, i)
}
go monitorWorker(wg, cs)
for i := range cs {
fmt.Println(i)
}
}
編集:これはOPの最初のコメントに対する回答です。
プログラムには、同期する必要のある3つの部分があります。まず、すべてのワーカーがデータを送信する必要があります。次に、印刷ループはそのデータを印刷する必要があります。次に、メイン関数が戻る必要があり、それによってプログラムが終了します。あなたの例では、すべてのワーカーがデータを送信し、すべてのデータが出力されますが、メッセージがメインに送信されることはなく、正常に返される必要があります。
私の例では、mainが印刷を行い、「monitorWorker」は、印刷する必要のあるすべてのデータを受信したときにmainに通知するだけです。このようにして、プログラムはデッドロックではなく正常に終了します。
印刷ループが別のゴルーチンにあることを主張する場合は、それを行うことができます。ただし、メインに戻るように、追加の通信をメインに送信する必要があります。この次の例では、チャネルを使用して、すべてのデータが印刷されるときにメインエンドを確保します。
package main
import (
"fmt"
"strconv"
"sync"
)
func worker(wg *sync.WaitGroup, cs chan string, i int) {
defer wg.Done()
cs <- "worker" + strconv.Itoa(i)
}
func monitorWorker(wg *sync.WaitGroup, cs chan string) {
wg.Wait()
close(cs)
}
func printWorker(cs <-chan string, done chan<- bool) {
for i := range cs {
fmt.Println(i)
}
done <- true
}
func main() {
wg := &sync.WaitGroup{}
cs := make(chan string)
for i := 0; i < 10; i++ {
wg.Add(1)
go worker(wg, cs, i)
}
go monitorWorker(wg, cs)
done := make(chan bool, 1)
go printWorker(cs, done)
<-done
}
チャネルが受信するメッセージの数がわかっている場合は、ループを制限するだけです。
//c is channel
for a := 1; a <= 3; a++{
fmt.Println(<-c)
}
また、別のチャネル(ワーカーのステータス)をワーカーに渡して、デッドロックの原因となるループを条件付きで停止することもできます。
追伸:それは単なる追加の迅速な解決策です。特にソリューションに対応しているわけではありません。