Create  Edit  Diff  FrontPage  Index  Search  Changes  Login

DeadLockInRuby

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: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呼び出しが原因ということがわかる。

後は何が悪いか自分で考える。

Last modified:2006/07/06 02:33:00
Keyword(s):
References: