RubyにおけるThreadクラス
スレッドの生成
Thread.new
Thread.start, Thread.fork
スレッドの状態
生きているスレッドの状態を文字列 "run"、"sleep", "aborting" のいずれかで返します。正常終了したスレッドに対して false、例外により終了したスレッドに対して nil を返します。
code:rb
# 実行中
Thread.current.status # => "run"
# 一時停止中
t1 = Thread.new { Thread.stop }
# ステータス確認
t1.status # => "sleep"
# スレッドを終了させる(正常終了)
t1.kill
# ステータス確認
t1.status # => false
# スレッド内で例外エラー
t2 = Thread.new { raise StandardError }
# ステータス確認
t2.status # => nil
"aborting" を出すのむずい。。。
code:rb
def foo
t = Thread.new do
begin
loop do
# 何らかの処理を繰り返す
sleep 1
end
ensure
sleep 10
end
end
# スレッドが実行中であることを確認
puts t.status # => "run"
# スレッドを終了させる
t.kill
# 終了処理中?
sleep 1
puts t.status # => "aborting" ??
# 正常終了済み
sleep 11
puts t.status # => false
end
スレッドの切り替え
リファレンスのサンプルコードが期待通りに動かなくて、ChatGPTに聞いてみた
こういうこと?
code:rb
thread1 = Thread.new do
5.times do |i|
Thread.pass # 他のスレッドに実行を譲る
sleep 1
end
end
thread2 = Thread.new do
5.times do |i|
Thread.pass # 他のスレッドに実行を譲る
sleep 1
end
end
例外発生時のスレッドのふるまい
code:raise_error_in_thread.rb
Thread.new { raise 'unexpected error' }
5.times do |i|
sleep 1
p i + 1
end
実行すると例外が発生したスレッド内は処理が終了し、その他のスレッド(メインスレッド)は処理を継続する
code:sh
% ruby raise_error_in_thread.rb
raise_error_in_thread.rb:1:in `block in <main>': unexpected error (RuntimeError)
1
2
3
4
5
デバッグモード -d で実行すると処理全体が終了する
code:sh
% ruby -d raise_error_in_thread.rb
raise_error_in_thread.rb:1:in `block in <main>': unexpected error (RuntimeError)
Exception `RuntimeError' at raise_error_in_thread.rb:3 - unexpected error
raise_error_in_thread.rb:1:in `block in <main>': unexpected error (RuntimeError)
あるいはコード上で Thread.abort_on_exception か Thread#abort_on_exception を true にすることで、スレッドでの例外発生時に処理全体を終了させるようにできる