Create  Edit  Diff  FrontPage  Index  Search  Changes  Login

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

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