原です。

タイムアウト処理をしようとして、次のようなクラスを作ってみました。

class TimeoutError < Exception
end
class Timeout
  def initialize(sec, msg = "timeout")
    @timer = Thread.start {
      sleep(sec)
      raise TimeoutError, msg
    }
  end
  def off
    Thread.kill @timer
    @timer = nil
  end
end

これで、

timer = Timeout.new(10)
10秒で行なえなければ例外を発生させる処理
timer.off

でうまくいくはずでした。これだと複数のタイマーを同時に
かけられてなかな面白い。

ところが、実際は他スレッドの例外は捕捉できないのです。
つまり、

begin
  Thread.start {
    raise "Exception!"
  }
rescue
  print "rescue: #$!\n"
ensure
  print "ensure: #$!\n"
end

は、ensure 節は実行されるけど、rescue 節は動きません。
(throw - catch でも同様です。)


で、質問です。これは仕様でしょうか?だとするとタイムアウト
処理はどう書くのがいいですか?


こういうのも考えたけど、あまりかっこ良くないですね。

def timeout(sec, msg = "timeout")
  n = sec * 10
  i = 0
  x = Thread.start { yield }
  while i < n
    sleep 0.1
    return unless x.status
    i += 1
  end
  Thread.kill x
  raise TimeoutError, msg
end

timeout(10) {
  10秒で行なえなければ例外を発生させる処理
}