LoginSignup
4
4

More than 5 years have passed since last update.

スレッドをまたいだ大域脱出はエラーになるのでスレッドのブロックぎりぎりに大域脱出しよう

Posted at

当たり前と言えば当たり前なんですけど。

スレッドをまたぐ大域脱出

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

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4