Code Fix

中級

sync: negative WaitGroup counter パニックの原因と直し方

sync.WaitGroupのDone()はAdd()で加算した回数より多く呼ぶとカウンタが負になり、実行時にパニックします。goroutineの数とAddで加算する数が一致していないと発生します。

エラーメッセージの読み方

panic: sync: negative WaitGroup counter
panic
パニック — 実行時に回復不能な状態になったことを示します。deferとrecoverで捕まえない限り、そのままプロセスが終了します
sync: negative WaitGroup counter
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  package main
 2  
 3  import "sync"
 4  
 5  func main() {
 6  	var wg sync.WaitGroup
 7  	wg.Add(1)
 8  	wg.Done()
 9  	wg.Done()
         ^
10  }
panic: sync: negative WaitGroup counterAdd(1)に対しDoneを2回呼んでいる

Add(1)に対してDoneを2回呼ぶと、カウンタが-1になってしまい実行時にパニックします。

直し方: wg.Done()(空) にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  package main
 2  
 3  import "sync"
 4  
 5  func main() {
 6  	var wg sync.WaitGroup
 7  	wg.Add(2)
 8  	wg.Done()
 9  	wg.Done()
10  	wg.Done()
         ^
11  }
panic: sync: negative WaitGroup counterAdd(2)に対しDoneを3回呼んでいる

Add(2)で2つ分のgoroutineを待つつもりが、Doneを3回呼ぶとカウンタが負になります。

直し方: wg.Done()(空) にします。

この問題を解いてみる →

パターン3

 1  package main
 2  
 3  import "sync"
 4  
 5  func main() {
 6  	var wg sync.WaitGroup
 7  	wg.Add(3)
 8  	wg.Done()
 9  	wg.Done()
10  	wg.Done()
11  	wg.Done()
         ^
12  }
panic: sync: negative WaitGroup counterAdd(3)に対しDoneを4回呼んでいる

AddとDoneの呼び出し回数の対応が崩れると、WaitGroupは静かに壊れるのではなく即座にパニックで教えてくれます。

直し方: wg.Done()(空) にします。

この問題を解いてみる →

パターン4

 1  package main
 2  
 3  import "sync"
 4  
 5  func main() {
 6  	var wg sync.WaitGroup
 7  	wg.Add(1)
 8  	wg.Done()
 9  	wg.Done()
         ^
10  }
panic: sync: negative WaitGroup counterAdd(1)に対しDoneを2回呼んでいる

goroutineの数とAddで加算する数が一致していないと、このパニックの原因になります。

直し方: wg.Done()(空) にします。

この問題を解いてみる →

パターン5

 1  package main
 2  
 3  import "sync"
 4  
 5  func main() {
 6  	var wg sync.WaitGroup
 7  	wg.Add(2)
 8  	wg.Done()
 9  	wg.Done()
10  	wg.Done()
         ^
11  }
panic: sync: negative WaitGroup counterAdd(2)に対しDoneを3回呼んでいる

defer wg.Done()を複数箇所に書いてしまうコピー&ペーストのミスも、この種のパニックの典型的な原因です。

直し方: wg.Done()(空) にします。

この問題を解いてみる →

よくある誤解

「Doneは呼びすぎても、カウンタが0で止まってくれるはず」という思い込みは誤りです。WaitGroupは呼び出し回数の対応を厳密にチェックしており、Addの回数を超えるDoneはその場でパニックを起こします。

まとめ

sync: negative WaitGroup counter パニックの原因と直し方は中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)