The Backyard - DeadLockInRuby Diff
- Added parts are displayed like this.
- Deleted parts are displayed
like this.
!RubyはRubyスレッドのデッドロックの検出機構を持つ
この記事ではRubyによるデッドロック検出時のエラーメッセージを説明する。
!!サンプル
以下のスクリプトを実行するとデッドロックが検出される。
#!/usr/local/bin/ruby -Ks
require 'thread'
q = Queue.new
Thread.new do
q.deq
end.join
このプログラムでは、メインスレッドはワーカスレッドの終了をThread#joinによって待っている。その一方でワーカスレッドはQueue#deqを呼ぶことでデータのエンキューを待つ。したがってどのスレッドも動けない。
この時、Rubyは以下のメッセージを表示して実行を中断する。
test>ruby dl.rb
deadlock 0xf63c8: sleep:- -/usr/local/lib/ruby/1.8/thread.rb:281/usr/local/lib/ruby/1.8/thread.rb:318
deadlock 0x10d678: sleep:J(0xf63c8) (main) - dl.rb:5
dl.rb:5:in `join': Thread(0x10d678): deadlock (fatal)
from dl.rb:5
!!出力されるメッセージの読み方
deadlockという行はすべてのスレッドの状態を示す。
deadlock 0xf63c8: sleep: - - /usr/local/……
A B C D E
* A: スレッドの参照
* B: スレッドの状態
* C: スレッドの待ち状態理由
** F(x): ファイルディスクリプタxで待ち
** S: IOセレクション
** T(x): タイムアウト待ち(xミリ秒)
** J(x): スレッドxに対してjoin
** P: プロセスウェイト
** -: それ以外
* D: メインスレッドかそれ以外か
* E: ソースファイル:行番号
!!メッセージ詳解
deadlock 0xf63c8: sleep:- - /usr/local/lib/ruby/1.8/thread.rb:318
deadlock 0x10d678: sleep:J(0xf63c8) (main) - dl.rb:5
まず、Dが(main)のメッセージに着目する。例では2行目のメッセージがメインスレッドの状態を示すメッセージである。
Eのソースファイルと行番号から、Thread.new ... end.join のjoinが問題だということがわかる。
メッセージのC(スレッドの待ち状態理由)は、J(0xf63c8)であるから、スレッド0xf63c8に対するjoinだということがわかる(joinだということはソースファイルの行からもわかる)。
次にスレッド0xf63c8を見るとthread.rbの318行目で-(その他)の理由でsleepしていることがわかる。
該当行は、Queue#pop(deqにaliasされている)内なので、4行目のdeq呼び出しが原因ということがわかる。
後は何が悪いか自分で考える。
この記事ではRubyによるデッドロック検出時のエラーメッセージを説明する。
!!サンプル
以下のスクリプトを実行するとデッドロックが検出される。
#!/usr/local/bin/ruby -Ks
require 'thread'
q = Queue.new
Thread.new do
q.deq
end.join
このプログラムでは、メインスレッドはワーカスレッドの終了をThread#joinによって待っている。その一方でワーカスレッドはQueue#deqを呼ぶことでデータのエンキューを待つ。したがってどのスレッドも動けない。
この時、Rubyは以下のメッセージを表示して実行を中断する。
test>ruby dl.rb
deadlock 0xf63c8: sleep:- -
deadlock 0x10d678: sleep:J(0xf63c8) (main) - dl.rb:5
dl.rb:5:in `join': Thread(0x10d678): deadlock (fatal)
from dl.rb:5
!!出力されるメッセージの読み方
deadlockという行はすべてのスレッドの状態を示す。
deadlock 0xf63c8: sleep: - - /usr/local/……
A B C D E
* A: スレッドの参照
* B: スレッドの状態
* C: スレッドの待ち状態理由
** F(x): ファイルディスクリプタxで待ち
** S: IOセレクション
** T(x): タイムアウト待ち(xミリ秒)
** J(x): スレッドxに対してjoin
** P: プロセスウェイト
** -: それ以外
* D: メインスレッドかそれ以外か
* E: ソースファイル:行番号
!!メッセージ詳解
deadlock 0xf63c8: sleep:- - /usr/local/lib/ruby/1.8/thread.rb:318
deadlock 0x10d678: sleep:J(0xf63c8) (main) - dl.rb:5
まず、Dが(main)のメッセージに着目する。例では2行目のメッセージがメインスレッドの状態を示すメッセージである。
Eのソースファイルと行番号から、Thread.new ... end.join のjoinが問題だということがわかる。
メッセージのC(スレッドの待ち状態理由)は、J(0xf63c8)であるから、スレッド0xf63c8に対するjoinだということがわかる(joinだということはソースファイルの行からもわかる)。
次にスレッド0xf63c8を見るとthread.rbの318行目で-(その他)の理由でsleepしていることがわかる。
該当行は、Queue#pop(deqにaliasされている)内なので、4行目のdeq呼び出しが原因ということがわかる。
後は何が悪いか自分で考える。