alarm(2)
Ruby で POSIX (または類似のもの)への移植可能なインターフェースを探しています。つまり、バックグラウンド タイマーを設定して、n秒後に現在のプロセスにシグナルを送信できるようにしたいと考えています。
2006 年の ruby-talk リストで、 を使用した解決策を提供する良い議論を見つけましdl/import
たが、これはちょっとしたハック (巧妙なハックではありますが) であり、あまり移植性がありません。
非常に悪意のあるTimeout
モジュールを見てきましたが、従来のインタープリターでは問題なく動作しますが、JRuby の下では機能しません。私のプログラムは、Readline ライブラリを使用する小さなコマンドライン シェルです。
TIMEOUT = 5 # seconds
loop do
input = nil
begin
Timeout.timeout(TIMEOUT) do
input = Readline::readline('> ', nil)
end
rescue Timeout::Error
puts "Timeout"
next
end
# do something with input
end
JRuby では、プロセスがreadline
呼び出しでブロックされ、 Timeout::Error
(a) タイマーが期限切れになり、(b) ユーザーが新しい行を入力した後にのみスローされるようです。そして例外は救出されません。うーん。
だから私はこの回避策を思いついた:
require 'readline'
class TimeoutException < Exception ; end
TIMEOUT = 5 # seconds
loop do
input = nil
start_time = Time.now
thread = Thread.new { input = Readline::readline('> ', nil) }
begin
while thread.alive? do
sleep(1) # prevent CPU from melting
raise TimeoutException if(Time.now - start_time > TIMEOUT)
end
rescue TimeoutException
thread.exit
puts "Timeout"
end
# do something with input
end
これは...不格好です(礼儀正しくしましょう)。私はただ欲しいalarm(2)
!このためにコア以外のライブラリ (Terminator など) をドラッグしたくありません。より良い方法はありますか?
編集:別の代替手段を取得できません-スリープしてからプロセスにシグナルを送信するスレッドを作成する-JRubyの下でも動作します。JRuby はシグナルを食べますか? 例:
SIG = 'USR2'
Signal.trap(SIG) { raise }
Process.kill(SIG, Process.pid)
JRuby は単純に戻り、Ruby は予想される「ハンドルされていない例外」エラーを返します。