Ruby 2.1.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > 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 節が実行されます。 これはスレッドが正常に終了する時はもちろんですが、他のスレッドから Thread#kill などによって終了させられた時も同様に実行されます。
メインスレッドの終了時の詳細に関しては 終了処理 を参照して下さい。
個々のスレッドは、以下の実行状態を持ちます。これらの状態は Object#inspect や Thread#status によって見ることができます。
p Thread.new {sleep 1} # => #<Thread:0xa039de0 sleep>
生成されたばかりのスレッドや Thread#run や Thread#wakeup で起こされたスレッドはこの状態です。 Thread#join でスレッドの終了を待っているスレッドもスレッドの 終了によりこの状態になります。 この状態のスレッドは「生きて」います。
Thread.stop や Thread#join により停止されたスレッ ドはこの状態になります。 この状態のスレッドは「生きて」います。
Thread#kill 等で終了されるスレッドは一時的にこの状態になりま す。この状態から停止状態(sleep)になることもあります。 この状態のスレッドはまだ「生きて」います。
Thread#kill 等で終了したスレッドはこの状態になります。この状 態のスレッドはどこからも参照されていなければ GC によりメモリ上から なくなります。 この状態のスレッドは「死んで」います。
@todo
DEBUG -> Integer
[permalink][rdoc]スレッドのデバッグレベルを返します。
使用するためには、THREAD_DEBUG を -1 にして Ruby をコンパイルする必要が あります。
DEBUG=(val)
[permalink][rdoc]スレッドのデバッグレベルを val に設定します。
使用するためには、THREAD_DEBUG を -1 にして Ruby をコンパイルする必要が あります。
abort_on_exception -> bool
[permalink][rdoc]abort_on_exception=(newstate)
真の時は、いずれかのスレッドが例外によって終了した時に、インタプリタ 全体を中断させます。false の場合、あるスレッドで起こった例外は、Thread#join などで検出されない限りそのスレッドだけをなにも警告を出さずに終了させます。
デフォルトは false です。
Thread/例外発生時のスレッドの振る舞いを参照してください。
current -> Thread
[permalink][rdoc]現在実行中のスレッド(カレントスレッド)を返します。
p Thread.current #=> #<Thread:0x4022e6fc run>
exclusive { ... } -> object
[permalink][rdoc]VM グローバルの Mutex をロックし、ブロックを実行します。
このクラスメソッドの挙動は 1.8 以前とは違います。 Thread.exclusive は VM グローバルの Thread::MUTEX_FOR_THREAD_EXCLUSIVE の synchronize を呼び出しているだけで、Thread.exclusive していないスレッドは動きます。 Mutex や Monitor などの他の排他制御の方法を検討してください。
exit -> ()
[permalink][rdoc]カレントスレッドに対して Thread#exit を呼びます。
start(*arg) {|*arg| ... } -> Thread
[permalink][rdoc]fork(*arg) {|*arg| ... } -> Thread
スレッドを生成して、ブロックの評価を開始します。 生成したスレッドを返します。
基本的に Thread.new と同じですが、 new メソッドと違い initialize メソッドを呼びません。
注意:
例えば、以下のコードは間違いです。スレッドの実行が開始される前に 変数 i が書き変わる可能性があるからです。
for i in 1..5 Thread.start { p i } end
上の例は以下のように書き直すべきです。
for i in 1..5 Thread.start(i) {|t| p t } end
handle_interrupt(hash) { ... } -> object
[permalink][rdoc]スレッドの割り込みのタイミングを引数で指定した内容に変更してブロックを 実行します。
「割り込み」とは、非同期イベントや Thread#raise や Thread#kill、Signal.#trap(未サポート)、メインスレッドの終了 (メインスレッドが終了すると、他のスレッドも終了されます)を意味します。
すぐに割り込みます。
ブロッキング処理(後述)の間は割り込みが発生します。
まったく割り込みません。
「ブロッキング処理」とは、読み込み処理や書き込み処理のような呼び出し元 のスレッドをブロックするような処理を意味します。CRuby の実装では、GVL を解放して実行する処理は全てブロッキング処理に含まれます。
また、マスクされた非同期割り込みは再度有効にされるまで延期されます。本 メソッドは sigprocmask(3) に似ています。
非同期割り込みの利用は難しいため、スレッド間での通信を実現する場合はま ずはキューのような他の方法を検討してください。それでも非同期割り込みを 利用する場合は本メソッドをよく理解してから利用してください。
例:Thread#raise 発生のタイミングを制御する例
th = Thread.new do Thead.handle_interrupt(RuntimeError => :never) { begin # 安全にリソースの割り当てが可能 Thread.handle_interrupt(RuntimeError => :immediate) { # ... } ensure # 安全にリソースの解放が可能 end } end Thread.pass # ... th.raise "stop"
RuntimeError を無視(延期)している間はリソースの割り当てや ensure 節でリソースの解放を安全に行う事ができます。
例:TimeoutError 発生のタイミングを制御する例
require 'timeout' Thread.handle_interrupt(TimeoutError => :never) { timeout(10){ # TimeoutError => :never の指定により、ここでは TimeoutError が発生しない。 Thread.handle_interrupt(TimeoutError => :on_blocking) { # :on_blocking な処理は TimeoutError が発生し得る。 } # TimeoutError => :never の指定により、ここでは TimeoutError が発生しない。 } }
この例を ensure 節での TimeoutError 発生に応用する事でリソースリー クに備える事ができます。Timeout.#timeout はスレッドを使って実装さ れているため、Thread.handle_interrupt による制御が有効です。
It's possible to stack multiple levels of ::handle_interrupt blocks in order to control more than one ExceptionClass and TimingSymbol at a time.
Thread.handle_interrupt(FooError => :never) { Thread.handle_interrupt(BarError => :never) { # FooError and BarError are prohibited. } }
本メソッドでは引数 hash のキーに指定した例外クラスの全てのサブクラスが 処理の対象になります。
例:
Thread.handle_interrupt(Exception => :never) { # Exception を継承する全ての例外クラスの例外の発生を延期。 }
[SEE_ALSO] Thread.pending_interrupt?, Thread#pending_interrupt?
kill(thread) -> Thread
[permalink][rdoc]指定したスレッド thread に対して Thread#exit を呼びます。終了したスレッドを返します。
th = Thread.new do end p Thread.kill(th) #=> #<Thread:0x40221bc8 dead>
list -> [Thread]
[permalink][rdoc]全ての生きているスレッドを含む配列を生成して返します。aborting 状態であるスレッド も要素に含まれます。
Thread.new do sleep end sleep 0.1 p Thread.list #=> [#<Thread:0x40377a54 sleep>, #<Thread:0x4022e6fc run>]
main -> Thread
[permalink][rdoc]メインスレッドを返します。
p Thread.main #=> #<Thread:0x4022e6fc run>
new(*arg) {|*arg| ... } -> Thread
[permalink][rdoc]スレッドを生成して、ブロックの評価を開始します。 生成したスレッドを返します。
注意:
例えば、以下のコードは間違いです。スレッドの実行が開始される前に 変数 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
[permalink][rdoc]他のスレッドに実行権を譲ります。実行中のスレッドの状態を変えずに、 他の実行可能状態のスレッドに制御を移します。
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
pending_interrupt?(error = nil) -> boolean
[permalink][rdoc]非同期割り込みのキューが空かどうかを返します。
Thread.handle_interrupt は非同期割り込みの発生を延期させるのに使 用しますが、本メソッドは任意の非同期割り込みが存在するかどうかを確認す るのに使用します。
本メソッドが true を返した場合、Thread.handle_interrupt で例外の 発生を延期するブロックを終了すると延期させられていた例外を発生させるこ とができます。
例: 延期させられていた例外をただちに発生させる。
def Thread.kick_interrupt_immediately Thread.handle_interrupt(Object => :immediate) { Thread.pass } end
th = Thread.new{ Thread.handle_interrupt(RuntimeError => :on_blocking){ while true ... # ここまでで割り込みが発生しても安全な状態になった。 if Thread.pending_interrupt? Thread.handle_interrupt(Object => :immediate){} end ... end } } ... th.raise # スレッド停止。
この例は以下のように記述する事もできます。
flag = true th = Thread.new{ Thread.handle_interrupt(RuntimeError => :on_blocking){ while true ... # ここまでで割り込みが発生しても安全な状態になった。 break if flag == false ... end } } ... flag = false # スレッド停止
[SEE_ALSO] Thread#pending_interrupt?, Thread.handle_interrupt
stop -> nil
[permalink][rdoc]他のスレッドから Thread#run メソッドで再起動されるまで、カレ ントスレッドの実行を停止します。
self[name] -> object | nil
[permalink][rdoc]name に対応したスレッドに固有のデータを取り出します。 name に対応するスレッド固有データがなければ nil を返し ます。
self[name] = val
[permalink][rdoc]val を name に対応するスレッド固有のデータとして格納します。
abort_on_exception -> bool
[permalink][rdoc]abort_on_exception=(newstate)
真の場合、そのスレッドが例外によって終了した時に、インタプリタ 全体を中断させます。false の場合、あるスレッドで起こった例 外は、Thread#join などで検出されない限りそのスレッ ドだけをなにも警告を出さずに終了させます。
デフォルトは偽です。Thread/例外発生時のスレッドの振る舞いを参照してください。
add_trace_func(pr) -> Proc
[permalink][rdoc]スレッドにトレース用ハンドラを追加します。
追加したハンドラを返します。
[SEE_ALSO] Thread#set_trace_func Kernel.#set_trace_func
alive? -> bool
[permalink][rdoc]スレッドが「生きている」時、true を返します。
Thread#status が真を返すなら、このメソッドも真です。
backtrace -> [String] | nil
[permalink][rdoc]スレッドの現在のバックトレースを返します。
スレッドがすでに終了している場合は nil を返します。
backtrace_locations(start = 0, length = nil) -> [Thread::Backtrace::Location] | nil
[permalink][rdoc]backtrace_locations(range) -> [Thread::Backtrace::Location] | nil
スレッドの現在のバックトレースを Thread::Backtrace::Location の配 列で返します。
引数で指定した値が範囲外の場合、スレッドがすでに終了している場合は nil を返します。
Kernel.#caller_locations と似ていますが、本メソッドは self に限定 した情報を返します。
[SEE_ALSO] Thread::Backtrace::Location
exit -> self
[permalink][rdoc]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
[permalink][rdoc]スレッドが属している ThreadGroup オブジェクトを返します。 死んでいるスレッドは nil を返します。
p Thread.current.group == ThreadGroup::Default # => true
inspect -> String
[permalink][rdoc]自身を人間が読める形式に変換した文字列を返します。
join -> self
[permalink][rdoc]join(limit) -> self | nil
スレッド self の実行が終了するまで、カレントスレッドを停止し ます。self が例外により終了していれば、その例外がカレントス レッドに対して発生します。
limit を指定して、limit 秒過ぎても自身が終了しない場合、nil を返します。
以下は、生成したすべてのスレッドの終了を待つ例です。
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
[permalink][rdoc]name に対応したスレッドに固有のデータが定義されていれば true を返します。
keys -> [Symbol]
[permalink][rdoc]スレッド固有データに関連づけられたキーの配列を返します。キーは Symbol で返されます。
th = Thread.current th[:foo] = 'FOO' th['bar'] = 'BAR' p th.keys #=> [:bar, :foo]
pending_interrupt?(error = nil) -> bool
[permalink][rdoc]self の非同期例外のキューが空かどうかを返します。
[SEE_ALSO] Thread.pending_interrupt?
priority -> Integer
[permalink][rdoc]priority=(val)
スレッドの優先度を返します。この値の大きいほど優先度が高くなります。 メインスレッドのデフォルト値は 0 です。新しく生成されたスレッドは親スレッドの priority を引き継ぎます。
raise(error_type, message, traceback) -> ()
[permalink][rdoc]自身が表すスレッドで強制的に例外を発生させます。
Thread.new { sleep 1 Thread.main.raise "foobar" } begin sleep rescue p $!, $@ end => #<RuntimeError: foobar> ["-:3"]
run -> self
[permalink][rdoc]停止状態(stop)のスレッドを再開させます。 Thread#wakeup と異なりすぐにスレッドの切り替え を行います。
safe_level -> Integer
[permalink][rdoc]self のセーフレベルを返します。カレントスレッドの safe_level は、$SAFE と同じです。
セーフレベルについてはセキュリティモデルを参照してください。
set_trace_func(pr) -> Proc | nil
[permalink][rdoc]スレッドにトレース用ハンドラを設定します。
nil を渡すとトレースを解除します。
設定したハンドラを返します。
[SEE_ALSO] Thread#add_trace_func Kernel.#set_trace_func
status -> String | false | nil
[permalink][rdoc]生きているスレッドの状態を文字列 "run"、"sleep", "aborting" のいず れかで返します。正常終了したスレッドに対して false、例外によ り終了したスレッドに対して nil を返します。
Thread#alive? が真を返すなら、このメソッドも真です。
stop? -> bool
[permalink][rdoc]スレッドが終了(dead)あるいは停止(stop)している時、true を返します。
thread_variable?(key) -> bool
[permalink][rdoc]引数 key で指定した名前のスレッドローカル変数が存在する場合に true、そ うでない場合に false を返します。
me = Thread.current me.thread_variable_set(:oliver, "a") me.thread_variable?(:oliver) # => true me.thread_variable?(:stanley) # => false
[注意]: Thread#[] でセットしたローカル変数(Fiber ローカル変数)が 対象ではない事に注意してください。
[SEE_ALSO] Thread#thread_variable_get, Thread#[]
thread_variable_get(key) -> object | nil
[permalink][rdoc]引数 key で指定した名前のスレッドローカル変数を返します。
[注意]: Thread#[] でセットしたローカル変数(Fiber ローカル変数)と 異なり、Fiber を切り替えても同じ変数を返す事に注意してください。
例:
Thread.new { Thread.current.thread_variable_set("foo", "bar") # スレッドローカル Thread.current["foo"] = "bar" # Fiber ローカル Fiber.new { Fiber.yield [ Thread.current.thread_variable_get("foo"), # スレッドローカル Thread.current["foo"], # Fiber ローカル ] }.resume }.join.value # => ['bar', nil]
この例の "bar" は Thread#thread_variable_get により得られ た値で、nil はThread#[] により得られた値です。
[SEE_ALSO] Thread#thread_variable_set, Thread#[]
[SEE_ALSO] http://magazine.rubyist.net/?0041-200Special-note#l16
thread_variable_set(key, value)
[permalink][rdoc]引数 key で指定した名前のスレッドローカル変数に引数 value をセットしま す。
[注意]: Thread#[] でセットしたローカル変数(Fiber ローカル変数)と 異なり、セットした変数は Fiber を切り替えても共通で使える事に注意してく ださい。
[SEE_ALSO] Thread#thread_variable_get, Thread#[]
value -> object
[permalink][rdoc]スレッド 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
[permalink][rdoc]停止状態(stop)のスレッドを実行可能状態(run)にします。
MUTEX_FOR_THREAD_EXCLUSIVE -> Mutex
[permalink][rdoc]Thread.exclusive用のMutexオブジェクトです。