Ruby 2.2.0 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > 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 DEBUG= abort_on_exception abort_on_exception= current exclusive exit fork start handle_interrupt kill list main new pass pending_interrupt? stop
インスタンスメソッド
[] []= abort_on_exception abort_on_exception= add_trace_func alive? backtrace backtrace_locations exit kill terminate group inspect join key? keys pending_interrupt? priority priority= raise run safe_level set_trace_func status stop? thread_variable? thread_variable_get thread_variable_set value wakeup
定数
MUTEX_FOR_THREAD_EXCLUSIVE

特異メソッド

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/例外発生時のスレッドの振る舞いを参照してください。

[PARAM] newstate:
スレッド実行中に例外発生した場合、インタプリタ全体を終了させるかどうかを true か false で指定します。
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 していないスレッドは動きます。 MutexMonitor などの他の排他制御の方法を検討してください。

exit -> ()[permalink][rdoc]

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

start(*arg) {|*arg| ... } -> Thread[permalink][rdoc]
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
handle_interrupt(hash) { ... } -> object[permalink][rdoc]

スレッドの割り込みのタイミングを引数で指定した内容に変更してブロックを 実行します。

「割り込み」とは、非同期イベントや Thread#raiseThread#killSignal.#trap(未サポート)、メインスレッドの終了 (メインスレッドが終了すると、他のスレッドも終了されます)を意味します。

[PARAM] hash:
例外クラスがキー、割り込みのタイミングを指定する Symbol が値の Hash を指定します。 値の内容は以下のいずれかです。
:immediate

すぐに割り込みます。

:on_blocking

ブロッキング処理(後述)の間は割り込みが発生します。

:never

まったく割り込みません。

「ブロッキング処理」とは、読み込み処理や書き込み処理のような呼び出し元 のスレッドをブロックするような処理を意味します。CRuby の実装では、GVL を解放して実行する処理は全てブロッキング処理に含まれます。

また、マスクされた非同期割り込みは再度有効にされるまで延期されます。本 メソッドは sigprocmask(3) に似ています。

[RETURN]
ブロックの評価結果を返します。
[EXCEPTION] ArgumentError:
ブロックを指定しなかった場合に発生します。

注意

非同期割り込みの利用は難しいため、スレッド間での通信を実現する場合はま ずはキューのような他の方法を検討してください。それでも非同期割り込みを 利用する場合は本メソッドをよく理解してから利用してください。

使い方

例: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 対策

例: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 による制御が有効です。

Stack control settings

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 を呼びます。終了したスレッドを返します。

[PARAM] thread:
終了したい Thread オブジェクトを指定します。
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]

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

[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[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) -> bool[permalink][rdoc]

非同期割り込みのキューが空かどうかを返します。

Thread.handle_interrupt は非同期割り込みの発生を延期させるのに使 用しますが、本メソッドは任意の非同期割り込みが存在するかどうかを確認す るのに使用します。

本メソッドが true を返した場合、Thread.handle_interrupt で例外の 発生を延期するブロックを終了すると延期させられていた例外を発生させるこ とができます。

[PARAM] error:
対象の例外クラスを指定します。省略した場合は全ての例外を対 象に確認を行います。

例: 延期させられていた例外をただちに発生させる。

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 を返し ます。

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

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

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

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

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

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

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

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

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

[SEE_ALSO] Thread#set_trace_func Kernel.#set_trace_func

alive? -> bool[permalink][rdoc]

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

例:

thr = Thread.new { }
thr.join                # => #<Thread:0x401b3fb0 dead>
Thread.current.alive?   # => true
thr.alive?              # => false

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 を返します。

[PARAM] start:
開始フレームの位置を数値で指定します。
[PARAM] length:
取得するフレームの個数を指定します。
[PARAM] range:
取得したいフレームの範囲を示す Range オブジェクトを指定します。

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 を返します。

[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[permalink][rdoc]

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

[PARAM] name:
文字列か Symbol で指定します。
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 の非同期例外のキューが空かどうかを返します。

[PARAM] error:
対象の例外クラスを指定します。

[SEE_ALSO] Thread.pending_interrupt?

priority -> Integer[permalink][rdoc]
priority=(val)

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

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

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

[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[permalink][rdoc]

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

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

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

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

set_trace_func(pr) -> Proc | nil[permalink][rdoc]

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

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

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

[PARAM] pr:
トレースハンドラ(Proc オブジェクト) もしくは 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 を返します。

[PARAM] key:
変数名を StringSymbol で指定します。
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)にします。

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

定数

MUTEX_FOR_THREAD_EXCLUSIVE -> Mutex[permalink][rdoc]

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