ホームページ  >  記事  >  バックエンド開発  >  Go で WaitGroup を値で渡すとデッドロックが発生するのはなぜですか?また、それを解決するにはどうすればよいですか?

Go で WaitGroup を値で渡すとデッドロックが発生するのはなぜですか?また、それを解決するにはどうすればよいですか?

Linda Hamilton
Linda Hamiltonオリジナル
2024-10-28 18:56:29520ブラウズ

Why does passing a WaitGroup by value in Go lead to a deadlock, and how can it be resolved?

Go チャネルのデッドロック: 変数スコープの問題

Golang プログラムでは、チャネルはゴルーチン間の通信を容易にします。ただし、以下のコードに示すように、チャネルを誤って使用するとデッドロックが発生する可能性があります:

<br>package main</p>
<p>import (</p>
<pre class="brush:php;toolbar:false">"fmt"
"sync"

)

func Push(c chan int, wg sync.WaitGroup) {

for i := 0; i < 5; i++ {
    c <- i
}
wg.Done()

}

func pull(c chan int, wg sync.WaitGroup) {

for i := 0; i < 5; i++ {
    result, ok := <-c
    fmt.Println(result, ok)
}
wg.Done()

}

func main() {

var wg sync.WaitGroup
wg.Add(2)
c := make(chan int)

go push(c, wg)
go pull(c, wg)

wg.Wait() // Block the main thread until goroutines complete

}

このプログラムを実行すると、次のような問題が発生する可能性があります。次のエラー:

fatal error: all goroutines are asleep - deadlock!

このデッドロックが発生する理由を理解するために、コードを詳しく調べてみましょう:

  • main は、WaitGroup、チャネル c、およびプッシュおよびプル用のゴルーチンを作成します。
  • プッシュ関数とプル関数は、WaitGroup を使用して実行を同期します。
  • プッシュ関数はループ内で c に値を送信し、wg.Done() を呼び出して完了を通知します。
  • プル関数は c から値を受け取り、それらを出力します。また、wg.Done() で完了を通知します。

問題は、WaitGroup がゴルーチンにどのように渡されるかにあります。アンパサンド (&) なしで値が渡される場合、その値は参照ではなく値によって渡されます。この場合、WaitGroup のコピーがゴルーチンごとに作成されます。

その結果、各ゴルーチンが wg.Done() を呼び出すと、WaitGroup のローカル コピーが変更されます。メインスレッドは、wg がすべてのゴルーチンの終了を示すまで待機するため、どちらのゴルーチンも元の WaitGroup を更新しないため、無限に待機します。これによりデッドロックが発生します。

この問題を解決するには、WaitGroup を参照で渡す必要があります。これにより、両方のゴルーチンが WaitGroup の同じインスタンスを変更し、その完了をメイン スレッドに正しく通知することが保証されます。

修正を加えたコードの改訂版は次のとおりです。

<br>パッケージ main</p>
<p>import (</p>
<pre class="brush:php;toolbar:false">"fmt"
"sync"

)

func Push(c chan int, wg *sync.WaitGroup) {

for i := 0; i < 5; i++ {
    c <- i
}
wg.Done()

}

func pull(c chan int, wg *sync.WaitGroup) {

for i := 0; i < 5; i++ {
    result, ok := <-c
    fmt.Println(result, ok)
}
wg.Done()

}

func main() {

var wg sync.WaitGroup
wg.Add(2)
c := make(chan int)

go push(c, &wg) // Pass the WaitGroup by reference using the ampersand
go pull(c, &wg) // Pass the WaitGroup by reference using the ampersand

wg.Wait()

}

WaitGroup を参照渡しすることで、メインスレッドが両方のゴルーチンがいつタスクを完了したかを正確に判断できるようになり、デッドロックが回避されます。

以上がGo で WaitGroup を値で渡すとデッドロックが発生するのはなぜですか?また、それを解決するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。