Go チャネルのデッドロック エラー
Go では、チャネルはゴルーチン間の通信手段を提供します。ただし、チャネルを不適切に使用すると、ゴルーチンが無期限にブロックされるデッドロックが発生する可能性があります。
チャネルでデッドロックが発生する一般的な原因の 1 つは、ゴルーチン関数でポインターの代わりに値の型を渡す場合です。これは、Go が値の型を値で渡すため、つまり値のコピーが作成されるためです。
次の例を考えてみましょう:
<code class="go">import ( "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() }</code>
プログラムを実行するとデッドロック エラーが発生します:
0 true 1 true 2 true 3 true 4 true throw: all goroutines are asleep - deadlock!
デッドロックは、WaitGroup が値としてプッシュ関数とプル関数に渡されるために発生します。 WaitGroup がいずれかのゴルーチンで更新されても、他のゴルーチンには値のコピーがあるため、その変更は反映されません。
デッドロックを解決するには、WaitGroup をポインターとして渡す必要があります。これにより、両方のゴルーチンが WaitGroup の同じインスタンス上で動作することが保証されます。
コードの修正バージョンは次のとおりです:
<code class="go">import ( "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() }</code>
以上がポインターの代わりに値を渡すと Go チャネルでデッドロックが発生するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。