Code Fix

中級

all goroutines are asleep - deadlock! の原因と直し方

バッファなしチャネルへの送信は、受信するgoroutineが存在するまでブロックします。受信側のgoroutineを起動し忘れると、送信だけが永遠にブロックしデッドロックとして検出されます。

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

fatal error: all goroutines are asleep - deadlock!
fatal error
ランタイムが検出した致命的な状態 — panicとは別に、goroutineの実行が続けられなくなったことをGoランタイム自身が検出したことを示します
all goroutines are asleep - deadlock!
詳細メッセージ — 何が起きたか

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

パターン1

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan int)
 5  	                       
                ^
 6  	<-ch
 7  }
fatal error: all goroutines are asleep - deadlock!

バッファなしチャネルへの受信は、送信するgoroutineが無いと永遠にブロックします。goで送信側を別goroutineとして起動する必要があります。

直し方: (空)go func() { ch <- 1 }() にします。

この問題を解いてみる →

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

パターン2

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan string)
 5  	                          
                  ^
 6  	<-ch
 7  }
fatal error: all goroutines are asleep - deadlock!

送信をgoroutineにせず同じgoroutineでch <- "go"と書いても、受信側が無いので同様にブロックしたままです。

直し方: (空)go func() { ch <- "go" }() にします。

この問題を解いてみる →

パターン3

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan bool)
 5  	                          
                  ^
 6  	<-ch
 7  }
fatal error: all goroutines are asleep - deadlock!

デッドロックはpanicではなくfatal errorとしてGoランタイム自身が検出し、プロセス全体を終了させます。

直し方: (空)go func() { ch <- true }() にします。

この問題を解いてみる →

パターン4

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan int)
 5  	                        
                 ^
 6  	<-ch
 7  }
fatal error: all goroutines are asleep - deadlock!

送信も受信もされないままメインgoroutineが止まると、他に動けるgoroutineが無いためランタイムがデッドロックと判断します。

直し方: (空)go func() { ch <- 42 }() にします。

この問題を解いてみる →

パターン5

 1  package main
 2  
 3  func main() {
 4  	ch := make(chan float64)
 5  	                          
                  ^
 6  	<-ch
 7  }
fatal error: all goroutines are asleep - deadlock!

型がfloat64でも同じで、受信を待つ側だけがいて送信するgoroutineが存在しなければ必ず止まります。

直し方: (空)go func() { ch <- 3.14 }() にします。

この問題を解いてみる →

よくある誤解

「チャネルへの送信は、受け取り手がいなくても一旦キューに積まれて先に進めるはず」という思い込みは誤りです。バッファなしチャネルは送信と受信が同時に成立して初めて完了する同期的な操作で、受信側が居ないと送信側は永遠にブロックします。

まとめ

all goroutines are asleep - deadlock!は中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

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