スレッド
スレッドとはメモリ空間を共有して同時に実行される制御の流れです。 Ruby ではスレッドはThread クラスのインスタンスとして表されます。
実装
Ruby のスレッドはユーザレベルで実装されており、 全プラットホーム上において同じ挙動を示します。 Ruby インタプリタは時分割でスレッドを実行しますので、 スレッドを使うことで実行速度が速くなることはありません。
スケジューリング
Ruby のスレッドスケジューリングは優先順位付のラウンドロビンです。一定 時間毎、あるいは実行中のスレッドが権利を放棄したタイミングでスケジュー リングが行われ、その時点で実行可能なスレッドのうち最も優先順位が高いも のにコンテキストが移ります。
メインスレッド
プログラムの開始と同時に生成されるスレッドを「メインスレッド」と呼 びます。なんらかの理由でメインスレッドが終了する時には、他の全てのスレッ ドもプログラム全体も終了します。ユーザからの割込みによって発生した例外 はメインスレッドに送られます。
スレッドの終了
スレッドの起動時に指定したブロックの実行が終了するとスレッドの実行も終 了します。ブロックの終了は正常な終了も例外などによる異常終了も含みます。
例外発生時のスレッドの振る舞い
あるスレッドで例外が発生し、そのスレッド内で rescue で捕捉されなかっ た場合、通常はそのスレッドだけがなにも警告なしに終了されます。ただ しその例外で終了するスレッドを Thread#join で待っている他の スレッドがある場合、その待っているスレッドに対して、同じ例外が再度 発生します。
begin t = Thread.new do Thread.pass # メインスレッドが確実にjoinするように raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end
また、以下の 3 つの方法により、いずれかのスレッドが例外によって終 了した時に、インタプリタ全体を中断させるように指定することができま す。
- 組み込み変数 $DEBUG を真に設定する(デバッグモード) ruby インタプリタを -d オプション 付きで起動した場合も同様。 (オプションの詳細に関してはRubyの起動 を参照)
- Thread.abort_on_exception でフラグを設定する。
- Thread#abort_on_exception で指定 したスレッドのフラグを設定する。
上記3つのいずれかが設定されていた場合、インタプリタ全体が中断されます。
スレッド終了時の ensure 節の実行
スレッド終了時には ensure 節が実行されます。 これはスレッドが正常に終了する時はもちろんですが、他のスレッドから Thread#kill などによって終了させられた時も同様に実行されます。 Thread#kill! が呼ばれた時はensure 節が実行されません。
ただしメインスレッドに対して Thread#kill! が呼ばれても ensure 節が実行されます。 メインスレッドの終了時の詳細に関しては 終了処理 を参照して下さい。
スレッドの状態
個々のスレッドは、以下の実行状態を持ちます。これらの状態は Object#inspect や Thread#status によって見ることができます。
p Thread.new {sleep 1} # => #<Thread:0xa039de0 sleep>
- run (実行or実行可能状態)
-
生成されたばかりのスレッドや Thread#run や Thread#wakeup で起こされたスレッドはこの状態です。 Thread#join でスレッドの終了を待っているスレッドもスレッドの 終了によりこの状態になります。 この状態のスレッドは「生きて」います。
- sleep (停止状態)
-
Thread.stop や Thread#join により停止されたスレッ ドはこの状態になります。 この状態のスレッドは「生きて」います。
- aborting (終了処理中)
-
Thread#kill 等で終了されるスレッドは一時的にこの状態になりま す。この状態から停止状態(sleep)になることもあります。 この状態のスレッドはまだ「生きて」います。
- dead (終了状態)
-
Thread#kill 等で終了したスレッドはこの状態になります。この状 態のスレッドはどこからも参照されていなければ GC によりメモリ上から なくなります。 この状態のスレッドは「死んで」います。
デッドロックの検出
ruby はデッドロックを検出します。デッドロックを検出した場合、例外 fatal が 発生してプロセスは終了します。デッドロックの条件は以下のとおりです。
- スレッドが複数ある
- すべてのスレッドが sleep (停止状態) である
- すべてのスレッドが IO 待ちでない
メインスレッドだけが Thread.stop で停止している状態は sleep forever と同じと見なし、 fatal は発生しません。