当たり前と言えば当たり前なんですけど。
スレッドをまたぐ大域脱出
Threadブロックよりも外にあるcatch(:out_of_thread)へ脱出しようとするとArgumentErrorエラーになります。
pry(main)> catch(:out_of_thread) do
pry(main)* Thread.start do
pry(main)* catch(:inside_of_thread) do
pry(main)* loop do
pry(main)* sleep 2
pry(main)* throw(:out_of_thread)
pry(main)* end
pry(main)* end
pry(main)* end
pry(main)* p Thread.list
pry(main)* Thread.list.each{ |th| th.join unless th == Thread.main}
pry(main)* end
[#<Thread:0x007f9dda0677a8 run>, #<Thread:0x007f9ddc2256b0 run>]
ArgumentError: uncaught throw :out_of_thread
スレッドをまたがない大域脱出
Threadブロックの内側にあるcatch(:inside_of_thread)へ脱出する場合には問題ありません。
pry(main)> catch(:out_of_thread) do
pry(main)* Thread.start do
pry(main)* catch(:inside_of_thread) do
pry(main)* loop do
pry(main)* sleep 2
pry(main)* throw(:inside_of_thread)
pry(main)* end
pry(main)* end
pry(main)* end
pry(main)* p Thread.list
pry(main)* Thread.list.each{ |th| th.join unless th == Thread.main}
pry(main)* end
[#<Thread:0x007f9dda0677a8 run>, #<Thread:0x007f9dda426ee8 run>]
=> [#<Thread:0x007f9dda0677a8 run>, #<Thread:0x007f9dda426ee8 dead>]
これで、throwすることにより、スレッド内の処理を全てすっ飛ばすことができます。
参考
module function Kernel.#throw
throw(tag, value = nil) -> ()
Kernel.#catchとの組み合わせで大域脱出を行います。 throw は同じ tag を指定した catch のブロックの終わりまでジャンプします。
throw は探索時に呼び出しスタックをさかのぼるので、 ジャンプ先は同じメソッド内にあるとは限りません。 もし ensure節 が存在するならジャンプ前に実行します。
同じ tag で待っている catch が存在しない場合は、例外で スレッドが終了します。
module function Kernel.#throw