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

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

Linda Hamilton
リリース: 2024-10-28 18:56:29
オリジナル
620 人が閲覧しました

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>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><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>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><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 サイトの他の関連記事を参照してください。

ソース:php.cn
前の記事:Go で関数呼び出しを引数として渡すにはどうすればよいですか? 次の記事:Go Web アプリケーションを IIS にデプロイする方法: HttpPlatformHandler を使用したステップバイステップ ガイド?
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
最新の問題
関連トピック
詳細>
人気のおすすめ
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート