class Thread

要約

スレッドを表すクラスです。スレッドとはメモリ空間を共有して同時に実行される制御の流れです。 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[permalink][rdoc]

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

スレッドのデバッグレベルが 0 のときはなにもしません。それ以外の場合は、スレッドのデバッグログを標準出力に出力します。初期値は 0 です。使用するためには、THREAD_DEBUG を -1 にして Ruby をコンパイルする必要があります。



Thread.DEBUG # => 0

[SEE_ALSO] Thread.DEBUG=

DEBUG=(val)[permalink][rdoc]

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

val が 真 のときは Integer に変換してから設定します。偽 のときは 0 を設定します。使用するためには、THREAD_DEBUG を -1 にして Ruby をコンパイルする必要があります。



Thread.DEBUG # => 0
Thread.DEBUG = 1
Thread.DEBUG # => 1

[SEE_ALSO] Thread.DEBUG

abort_on_exception -> bool[permalink][rdoc]
abort_on_exception=(newstate)

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

デフォルトは false です。

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

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


Thread.abort_on_exception # => false
Thread.abort_on_exception = true
Thread.abort_on_exception # => true
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 していないスレッドは動きます。 Thread::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

report_on_exception -> bool[permalink][rdoc]
report_on_exception=(newstate)

真の時は、いずれかのスレッドが例外によって終了した時に、その内容を $stderr に報告します。

デフォルトは false です。

Thread.new { 1.times { raise } }

は $stderr に以下のように出力します:

#<Thread:...> terminated with exception (report_on_exception is true):
Traceback (most recent call last):
        2: from -e:1:in `block in <main>'
        1: from -e:1:in `times'

これによってスレッドのエラーを早期に捕捉できるようになります。いくつかのケースでは、この出力を望まないかもしれません。出力を抑制するには複数の方法があります:

スレッドごとに設定する方法は Thread#report_on_exception= を参照してください。

[PARAM] newstate:
スレッド実行中に例外発生した場合、その内容を報告するかどうかを true か false で指定します。
stop -> nil[permalink][rdoc]

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



a = Thread.new { print "a"; Thread.stop; print "c" }
sleep 0.1 while a.status!='sleep'
print "b"
a.run
a.join
# => "abc"

[SEE_ALSO] Thread#run, Thread#wakeup

インスタンスメソッド

self[name] -> object | nil[permalink][rdoc]

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

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


[
  Thread.new { Thread.current["name"] = "A" },
  Thread.new { Thread.current[:name]  = "B" },
  Thread.new { Thread.current["name"] = "C" }
].each do |th|
  th.join
  puts "#{th.inspect}: #{th[:name]}"
end

# => #<Thread:0x00000002a54220 dead>: A
# => #<Thread:0x00000002a541a8 dead>: B
# => #<Thread:0x00000002a54130 dead>: C

Thread#[]Thread#[]= を用いたスレッド固有の変数は Fiber を切り替えると異なる変数を返す事に注意してください。


def meth(newvalue)
  begin
    oldvalue = Thread.current[:name]
    Thread.current[:name] = newvalue
    yield
  ensure
    Thread.current[:name] = oldvalue
  end
end

この関数に与えるブロックがFiberを切り替える場合は動的スコープとしては正しく動作しません。


f = Fiber.new {
  meth(1) {
    Fiber.yield
  }
}
meth(2) {
  f.resume
}
f.resume
p Thread.current[:name]
# => nil if fiber-local
# => 2 if thread-local (The value 2 is leaked to outside of meth method.)

Fiber を切り替えても同じ変数を返したい場合は Thread#thread_variable_getThread#thread_variable_set を使用してください。

Thread#[]=

self[name] = val[permalink][rdoc]

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

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

[SEE_ALSO] Thread#[]

abort_on_exception -> bool[permalink][rdoc]
abort_on_exception=(newstate)

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

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

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


thread = Thread.new { sleep 1 }
thread.abort_on_exception # => false
thread.abort_on_exception = true
thread.abort_on_exception # => true
add_trace_func(pr) -> Proc[permalink][rdoc]

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

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

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


th = Thread.new do
  class Trace
  end
  43.to_s
end
th.add_trace_func lambda {|*arg| p arg }
th.join

# => ["line", "example.rb", 4, nil, #<Binding:0x00007f98e107d0d8>, nil]
# => ["c-call", "example.rb", 4, :inherited, #<Binding:0x00007f98e1087448>, Class]
# => ["c-return", "example.rb", 4, :inherited, #<Binding:0x00007f98e1085d00>, Class]
# => ["class", "example.rb", 4, nil, #<Binding:0x00007f98e108f210>, nil]
# => ["end", "example.rb", 5, nil, #<Binding:0x00007f98e108e5e0>, nil]
# => ["line", "example.rb", 6, nil, #<Binding:0x00007f98e108d4b0>, nil]
# => ["c-call", "example.rb", 6, :to_s, #<Binding:0x00007f98e1097aa0>, Integer]
# => ["c-return", "example.rb", 6, :to_s, #<Binding:0x00007f98e1095cc8>, Integer]

[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 が真を返すなら、このメソッドも真です。

[SEE_ALSO] Thread#status, Thread#stop?

backtrace -> [String] | nil[permalink][rdoc]

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

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



class C1
  def m1
    sleep 5
  end
  def m2
    m1
  end
end

th = Thread.new {C1.new.m2; Thread.stop}
th.backtrace
# => [
#      [0] "(irb):3:in `sleep'",
#      [1] "(irb):3:in `m1'",
#      [2] "(irb):6:in `m2'",
#      [3] "(irb):10:in `block in irb_binding'"
#    ]

th.kill
th.backtrace   # => 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 に限定した情報を返します。



thread = Thread.new { sleep 1 }
thread.run
thread.backtrace_locations # => ["/path/to/test.rb:1:in `sleep'", "/path/to/test.rb:1:in `block in <main>'"]

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

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



a = Thread.current
a.inspect   # => "#<Thread:0x00007fdbaf07ddb0 run>"
b = Thread.new{}
b.inspect   # => "#<Thread:0x00007fdbaf8f7d10@(irb):3 dead>"
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 で指定します。


me = Thread.current
me[:oliver] = "a"
me.key?(:oliver)    # => true
me.key?(:stanley)   # => false
keys -> [Symbol][permalink][rdoc]

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

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

#=> [:bar, :foo]
name -> String[permalink][rdoc]

self の名前を返します。

[SEE_ALSO] Thread#name=

name=(name) -> String[permalink][rdoc]

self の名前を name に設定します。

プラットフォームによっては pthread やカーネルにも設定を行う場合があります。

[EXCEPTION] ArgumentError:
引数に ASCII 互換ではないエンコーディングのものを指定した場合に発生します。


a = Thread.new{}
a.name = 'named'
a.name      # => "named"
a.inspect   # => "#<Thread:0x00007f85ac8721f0@named@(irb):1 dead>"

[SEE_ALSO] Thread#name

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:
スレッドの優先度を指定します。プラットフォームに依存します。


Thread.current.priority   # => 0

count1 = count2 = 0
a = Thread.new do
      loop { count1 += 1 }
    end
a.priority = -1

b = Thread.new do
      loop { count2 += 1 }
    end
b.priority = -2
count1 = count2 = 0 # reset
sleep 1   # => 1
count1    # => 13809431
count2    # => 11571921
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"]
report_on_exception -> bool[permalink][rdoc]
report_on_exception=(newstate)

真の場合、そのスレッドが例外によって終了した時に、その内容を $stderr に報告します。

デフォルトはスレッド作成時の Thread.report_on_exception です。

[PARAM] newstate:
スレッド実行中に例外発生した場合、その内容を報告するかどうかを true か false で指定します。


a = Thread.new{ Thread.stop; raise }
a.report_on_exception = true
a.report_on_exception   # => true
a.run
# => #<Thread:0x00007fc3f48c7908@(irb):1 run> terminated with exception (report_on_exception is true):
#    Traceback (most recent call last):
#    (irb):1:in `block in irb_binding': unhandled exception
#    #<Thread:0x00007fc3f48c7908@(irb):1 dead>
b = Thread.new{ Thread.stop; raise }
b.report_on_exception = false
b.run   # => #<Thread:0x00007fc3f48aefc0@(irb):4 dead>

[SEE_ALSO] Thread.report_on_exception

run -> self[permalink][rdoc]

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

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


a = Thread.new { puts "a"; Thread.stop; puts "c" }
sleep 0.1 while a.status!='sleep'
puts "Got here"
a.run
a.join
# => a
# => Got here
# => c

[SEE_ALSO] Thread#wakeup, Thread.stop

safe_level -> Integer[permalink][rdoc]

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

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



thr = Thread.new { $SAFE = 1; sleep }
Thread.current.safe_level   # => 0
thr.safe_level              # => 1
set_trace_func(pr) -> Proc | nil[permalink][rdoc]

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

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

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



th = Thread.new do
  class Trace
  end
  2.to_s
  Thread.current.set_trace_func nil
  3.to_s
end
th.set_trace_func lambda {|*arg| p arg }
th.join

# => ["line", "example.rb", 2, nil, #<Binding:0x00007fc8de87cb08>, nil]
# => ["c-call", "example.rb", 2, :inherited, #<Binding:0x00007fc8de886770>, Class]
# => ["c-return", "example.rb", 2, :inherited, #<Binding:0x00007fc8de8844e8>, Class]
# => ["class", "example.rb", 2, nil, #<Binding:0x00007fc8de88e830>, nil]
# => ["end", "example.rb", 3, nil, #<Binding:0x00007fc8de88d6b0>, nil]
# => ["line", "example.rb", 4, nil, #<Binding:0x00007fc8de88c440>, nil]
# => ["c-call", "example.rb", 4, :to_s, #<Binding:0x00007fc8de896f30>, Integer]
# => ["c-return", "example.rb", 4, :to_s, #<Binding:0x00007fc8de894a50>, Integer]
# => ["line", "example.rb", 5, nil, #<Binding:0x00007fc8de967b08>, nil]
# => ["c-call", "example.rb", 5, :current, #<Binding:0x00007fc8de967798>, Thread]
# => ["c-return", "example.rb", 5, :current, #<Binding:0x00007fc8de9673b0>, Thread]
# => ["c-call", "example.rb", 5, :set_trace_func, #<Binding:0x00007fc8de966fc8>, Thread]
[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? が真を返すなら、このメソッドも真です。

例:

a = Thread.new { raise("die now") }
b = Thread.new { Thread.stop }
c = Thread.new { Thread.exit }
d = Thread.new { sleep }
d.kill                  #=> #<Thread:0x401b3678 aborting>
a.status                #=> nil
b.status                #=> "sleep"
c.status                #=> false
d.status                #=> "aborting"
Thread.current.status   #=> "run"

[SEE_ALSO] Thread#alive?, Thread#stop?

stop? -> bool[permalink][rdoc]

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



a = Thread.new { Thread.stop }
b = Thread.current
a.stop?   # => true
b.stop?   # => false

[SEE_ALSO] Thread#alive?, Thread#status

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] https://magazine.rubyist.net/articles/0041/0041-200Special-note.html

thread_variable_set(key, value)[permalink][rdoc]

引数 key で指定した名前のスレッドローカル変数に引数 value をセットします。

[注意]: Thread#[] でセットしたローカル変数(Fiber ローカル変数)と異なり、セットした変数は Fiber を切り替えても共通で使える事に注意してください。



thr = Thread.new do
  Thread.current.thread_variable_set(:cat, 'meow')
  Thread.current.thread_variable_set("dog", 'woof')
end
thr.join               # => #<Thread:0x401b3f10 dead>
thr.thread_variables   # => [:dog, :cat]

[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:
死んでいるスレッドに対して実行すると発生します。


c = Thread.new { Thread.stop; puts "hey!" }
sleep 0.1 while c.status!='sleep'
c.wakeup
c.join
# => "hey!"

[SEE_ALSO] Thread#run, Thread.stop

定数

MUTEX_FOR_THREAD_EXCLUSIVE -> Mutex[permalink][rdoc]

Thread.exclusive用のMutexオブジェクトです。 (private constant です。)