Ruby 1.9.3 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Threadクラス

class Thread

クラスの継承リスト: Thread < Object < Kernel < BasicObject

要約

スレッドを表すクラスです。スレッドとはメモリ空間を共有して同時に実行される制御の流れです。 Thread を使うことで並行プログラミングが可能になります。

実装

ネイティブスレッドを用いて実装されていますが、 現在の実装では Ruby VM は Giant VM lock (GVL) を有しており、同時に実行される ネイティブスレッドは常にひとつです。 ただし、IO 関連のブロックする可能性があるシステムコールを行う場合には GVL を解放します。その場合にはスレッドは同時に実行され得ます。 また拡張ライブラリから GVL を操作できるので、複数のスレッドを 同時に実行するような拡張ライブラリは作成可能です。

スケジューリング

Ruby のスレッドスケジューリングはネイティブスレッドのそれを利用しています。 よって詳細はプラットフォームに依存します。

メインスレッド

プログラムの開始と同時に生成されるスレッドを「メインスレッド」と呼 びます。なんらかの理由でメインスレッドが終了する時には、他の全てのスレッ ドもプログラム全体も終了します。ユーザからの割込みによって発生した例外 はメインスレッドに送られます。

スレッドの終了

スレッドの起動時に指定したブロックの実行が終了するとスレッドの実行も終 了します。ブロックの終了は正常な終了も例外などによる異常終了も含みます。

例外発生時のスレッドの振る舞い

あるスレッドで例外が発生し、そのスレッド内で rescue で捕捉されなかっ た場合、通常はそのスレッドだけがなにも警告なしに終了されます。ただ しその例外で終了するスレッドを Thread#join で待っている他の スレッドがある場合、その待っているスレッドに対して、同じ例外が再度 発生します。

begin
  t = Thread.new do
    Thread.pass    # メインスレッドが確実にjoinするように
    raise "unhandled exception"
  end
  t.join
rescue
  p $!  # => "unhandled exception"
end

また、以下の 3 つの方法により、いずれかのスレッドが例外によって終 了した時に、インタプリタ全体を中断させるように指定することができま す。

上記3つのいずれかが設定されていた場合、インタプリタ全体が中断されます。

スレッド終了時の ensure 節の実行

スレッド終了時には ensure 節が実行されます。 これはスレッドが正常に終了する時はもちろんですが、他のスレッドから Thread#kill などによって終了させられた時も同様に実行されます。

メインスレッドの終了時の詳細に関しては 終了処理 を参照して下さい。

スレッドの状態

個々のスレッドは、以下の実行状態を持ちます。これらの状態は Object#inspectThread#status によって見ることができます。

p Thread.new {sleep 1} # => #<Thread:0xa039de0 sleep>
run (実行or実行可能状態)

生成されたばかりのスレッドや Thread#runThread#wakeup で起こされたスレッドはこの状態です。 Thread#join でスレッドの終了を待っているスレッドもスレッドの 終了によりこの状態になります。 この状態のスレッドは「生きて」います。

sleep (停止状態)

Thread.stopThread#join により停止されたスレッ ドはこの状態になります。 この状態のスレッドは「生きて」います。

aborting (終了処理中)

Thread#kill 等で終了されるスレッドは一時的にこの状態になりま す。この状態から停止状態(sleep)になることもあります。 この状態のスレッドはまだ「生きて」います。

dead (終了状態)

Thread#kill 等で終了したスレッドはこの状態になります。この状 態のスレッドはどこからも参照されていなければ GC によりメモリ上から なくなります。 この状態のスレッドは「死んで」います。

デッドロックの検出

@todo

特異メソッド

DEBUG -> Integer

スレッドのデバッグレベルを返します。

使用するためには、THREAD_DEBUG を -1 にして Ruby をコンパイルする必要が あります。

DEBUG=(val)

スレッドのデバッグレベルを val に設定します。

使用するためには、THREAD_DEBUG を -1 にして Ruby をコンパイルする必要が あります。

abort_on_exception -> bool
abort_on_exception=(newstate)

真の時は、いずれかのスレッドが例外によって終了した時に、インタプリタ 全体を中断させます。false の場合、あるスレッドで起こった例外は、Thread#join などで検出されない限りそのスレッドだけをなにも警告を出さずに終了させます。

デフォルトは false です。

Thread/例外発生時のスレッドの振る舞い を参照してください。

[PARAM] newstate:
スレッド実行中に例外発生した場合、インタプリタ全体を終了させるかどうかを true か false で指定します。
current -> Thread

現在実行中のスレッド(カレントスレッド)を返します。

p Thread.current #=> #<Thread:0x4022e6fc run>
exclusive { ... } -> object

VM グローバルの Mutex をロックし、ブロックを実行します。

このクラスメソッドの挙動は 1.8 以前とは違います。 Thread.exclusive は VM グローバルの Thread::MUTEX_FOR_THREAD_EXCLUSIVE の synchronize を呼び出しているだけで、Thread.exclusive していないスレッドは動きます。 MutexMonitor などの他の排他制御の方法を検討してください。

exit -> ()

カレントスレッドに対して Thread#exit を呼びます。

start(*arg) {|*arg| ... } -> Thread
fork(*arg) {|*arg| ... } -> Thread

スレッドを生成して、ブロックの評価を開始します。 生成したスレッドを返します。

基本的に Thread.new と同じですが、 new メソッドと違い initialize メソッドを呼びません。

[PARAM] arg:
引数 arg はそのままブロックに渡されます。スレッドの開始と同時にその スレッド固有のローカル変数に値を渡すために使用します。
[EXCEPTION] ThreadError:
現在のスレッドが属する ThreadGroup が freeze されている場合に発生します。またブロックを与えられずに呼ばれた場合にも発生します。

注意:

例えば、以下のコードは間違いです。スレッドの実行が開始される前に 変数 i が書き変わる可能性があるからです。

for i in 1..5
   Thread.start { p i }
end

上の例は以下のように書き直すべきです。

for i in 1..5
   Thread.start(i) {|t| p t }
end
kill(thread) -> Thread

指定したスレッド thread に対して Thread#exit を呼びます。終了したスレッドを返します。

[PARAM] thread:
終了したい Thread オブジェクトを指定します。
th = Thread.new do
end

p Thread.kill(th)     #=> #<Thread:0x40221bc8 dead>
list -> [Thread]

全ての生きているスレッドを含む配列を生成して返します。aborting 状態であるスレッド も要素に含まれます。

Thread.new do
  sleep
end
sleep 0.1

p Thread.list   #=> [#<Thread:0x40377a54 sleep>, #<Thread:0x4022e6fc run>]
main -> Thread

メインスレッドを返します。

p Thread.main #=> #<Thread:0x4022e6fc run>
new(*arg) {|*arg| ... } -> Thread

スレッドを生成して、ブロックの評価を開始します。 生成したスレッドを返します。

[PARAM] arg:
引数 arg はそのままブロックに渡されます。スレッドの開始と同時にその スレッド固有のローカル変数に値を渡すために使用します。
[EXCEPTION] ThreadError:
現在のスレッドが属する ThreadGroup が freeze されている場合に発生します。またブロックを与えられずに呼ばれた場合にも発生します。

注意:

例えば、以下のコードは間違いです。スレッドの実行が開始される前に 変数 i が書き変わる可能性があるからです。

for i in 1..5
   Thread.new { p i }
end

上の例は以下のように書き直すべきです。

for i in 1..5
   Thread.new(i) {|t| p t }
end
pass -> nil

他のスレッドに実行権を譲ります。実行中のスレッドの状態を変えずに、 他の実行可能状態のスレッドに制御を移します。

Thread.new do
  (1..3).each{|i|
    p i
    Thread.pass
  }
  exit
end

loop do
  Thread.pass
  p :main
end

#=>
1
:main
2
:main
3
:main
stop -> nil

他のスレッドから Thread#run メソッドで再起動されるまで、カレ ントスレッドの実行を停止します。

インスタンスメソッド

self[name] -> object | nil

name に対応したスレッドに固有のデータを取り出します。 name に対応するスレッド固有データがなければ nil を返し ます。

[PARAM] name:
スレッド固有データのキーを文字列か Symbol で指定します。
self[name] = val

val を name に対応するスレッド固有のデータとして格納します。

[PARAM] name:
スレッド固有データのキーを文字列か Symbol で指定します。文字列を指定した場合は String#to_sym によりシンボルに変換されます。
[PARAM] val:
スレッド固有データを指定します。nil を指定するとそのスレッド固有データは削除されます。
abort_on_exception -> bool
abort_on_exception=(newstate)

真の場合、そのスレッドが例外によって終了した時に、インタプリタ 全体を中断させます。false の場合、あるスレッドで起こった例 外は、Thread#join などで検出されない限りそのスレッ ドだけをなにも警告を出さずに終了させます。

デフォルトは偽です。Thread/例外発生時のスレッドの振る舞い を参照してください。

[PARAM] newstate:
自身を実行中に例外発生した場合、インタプリタ全体を終了させるかどうかを true か false で指定します。
add_trace_func(pr) -> Proc

スレッドにトレース用ハンドラを追加します。

追加したハンドラを返します。

[PARAM] pr:
トレースハンドラ(Proc オブジェクト)

[SEE_ALSO] Thread#set_trace_func Kernel.#set_trace_func

alive? -> bool

スレッドが「生きている」時、true を返します。

Thread#status が真を返すなら、このメソッドも真です。

backtrace -> [String] | nil

スレッドの現在のバックトレースを返します。

スレッドがすでに終了している場合は nil を返します。

exit -> self
kill -> self
terminate -> self

スレッドの実行を終了させます。終了時に ensure 節が実行されます。

ただし、スレッドは終了処理中(aborting)にはなりますが、 直ちに終了するとは限りません。すでに終了している場合は何もしません。このメソッドにより 終了したスレッドの Thread#value の返り値は不定です。 自身がメインスレッドであるか最後のスレッドである場合は、プロセスを Kernel.#exit(0) により終了します。

Kernel.#exit と違い例外 SystemExit を発生しません。

th1 = Thread.new do
  begin
    sleep 10
  ensure
    p "this will be displayed"
  end
end

sleep 0.1
th1.kill

#=> "this will be displayed"

[SEE_ALSO] Kernel.#exit, Kernel.#exit!

group -> ThreadGroup | nil

スレッドが属している ThreadGroup オブジェクトを返します。 死んでいるスレッドは nil を返します。

p Thread.current.group == ThreadGroup::Default
# => true
inspect -> String

自身を人間が読める形式に変換した文字列を返します。

join -> self
join(limit) -> self | nil

スレッド self の実行が終了するまで、カレントスレッドを停止し ます。self が例外により終了していれば、その例外がカレントス レッドに対して発生します。

limit を指定して、limit 秒過ぎても自身が終了しない場合、nil を返します。

[PARAM] limit:
タイムアウトする時間を整数か小数で指定します。単位は秒です。
[EXCEPTION] ThreadError:
join を実行することによってデッドロックが起きる場合に発生します。またカレントスレッドを join したときにも発生します。

以下は、生成したすべてのスレッドの終了を待つ例です。

threads = []
threads.push(Thread.new { n = rand(5); sleep n; n })
threads.push(Thread.new { n = rand(5); sleep n; n })
threads.push(Thread.new { n = rand(5); sleep n; n })

threads.each {|t| t.join}
key?(name) -> bool

name に対応したスレッドに固有のデータが定義されていれば true を返します。

[PARAM] name:
文字列か Symbol で指定します。
keys -> [Symbol]

スレッド固有データに関連づけられたキーの配列を返します。キーは Symbol で返されます。

th = Thread.current
th[:foo] = 'FOO'
th['bar'] = 'BAR'
p th.keys

#=> [:bar, :foo]
priority -> Integer
priority=(val)

スレッドの優先度を返します。この値の大きいほど優先度が高くなります。 メインスレッドのデフォルト値は 0 です。新しく生成されたスレッドは親スレッドの priority を引き継ぎます。

[PARAM] val:
スレッドの優先度を指定します。プラットフォームに依存します。
raise(error_type, message, traceback) -> ()

自身が表すスレッドで強制的に例外を発生させます。

[PARAM] error_type:
Kernel.#raise を参照してください。
[PARAM] message:
Kernel.#raise を参照してください。
[PARAM] traceback:
Kernel.#raise を参照してください。
Thread.new {
  sleep 1
  Thread.main.raise "foobar"
}

begin
  sleep
rescue
  p $!, $@
end

=> #<RuntimeError: foobar>
   ["-:3"]
run -> self

停止状態(stop)のスレッドを再開させます。 Thread#wakeup と異なりすぐにスレッドの切り替え を行います。

[EXCEPTION] ThreadError:
死んでいるスレッドに対して実行すると発生します。
safe_level -> Integer

self のセーフレベルを返します。カレントスレッドの safe_level は、$SAFE と同じです。

セーフレベルについてはセキュリティモデルを参照してください。

set_trace_func(pr) -> Proc | nil

スレッドにトレース用ハンドラを設定します。

nil を渡すとトレースを解除します。

設定したハンドラを返します。

[PARAM] pr:
トレースハンドラ(Proc オブジェクト) もしくは nil

[SEE_ALSO] Thread#add_trace_func Kernel.#set_trace_func

status -> String | false | nil

生きているスレッドの状態を文字列 "run"、"sleep", "aborting" のいず れかで返します。正常終了したスレッドに対して false、例外によ り終了したスレッドに対して nil を返します。

Thread#alive? が真を返すなら、このメソッドも真です。

stop? -> bool

スレッドが終了(dead)あるいは停止(stop)している時、true を返します。

value -> object

スレッド self が終了するまで待ち(Thread#join と同じ)、 そのスレッドのブロックが返した値を返します。スレッド実行中に例外が 発生した場合には、その例外を再発生させます。

スレッドが Thread#kill によって終了した場合は、返り値は不定です。

以下は、生成したすべてのスレッドの終了を待ち結果を出力する例です。

threads = []
threads.push(Thread.new { n = rand(5); sleep n; n })
threads.push(Thread.new { n = rand(5); sleep n; n })
threads.push(Thread.new { n = rand(5); sleep n; n })

threads.each {|t| p t.value}

最後の行で、待ち合わせを行っていることがわかりにくいと思うなら以下 のように書くこともできます。

threads.each {|t| p t.join.value}
wakeup -> self

停止状態(stop)のスレッドを実行可能状態(run)にします。

[EXCEPTION] ThreadError:
死んでいるスレッドに対して実行すると発生します。

定数

MUTEX_FOR_THREAD_EXCLUSIVE -> Mutex

Thread.exclusive用のMutexオブジェクトです。

class Thread