質問

POSIX へのポータブルなインターフェイスを探しています alarm(2) (または同様の) Ruby の場合。つまり、バックグラウンドタイマーを設定して、実行後に現在のプロセスにシグナルを送信できるようにしたいと考えています。 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)!このために非コア ライブラリ (ターミネーターなど) をドラッグしたくありません。もっと良い方法はありますか?

編集:JRuby で動作させるために、スリープ状態にしてからプロセスにシグナルを送信するスレッドを作成するという別の選択肢もありません。JRuby はシグナルを食べますか?例:

SIG = 'USR2'
Signal.trap(SIG) { raise }
Process.kill(SIG, Process.pid)

JRuby は単に返すだけで、Ruby は予期された「未処理の例外」エラーを返します。

役に立ちましたか?

解決

X 秒後にプロセスにシグナルを送信するという大きな問題に対する答えがなくて申し訳ありませんが、入力を待機してから X 秒後にタイムアウトすることだけが必要のようです。この場合、Kernel.select を探していると思います:D

私は個人的にこれを使用したことはありませんが、「ノンブロッキング ゲット」についてグーグルで検索し、その後リンクを調べた結果、次の 2 つが非常に貴重な議論であることがわかりました。

http://www.ruby-forum.com/topic/126795 (マルチスレッド get についての議論)

http://www.ruby-forum.com/topic/121404 (Kernel.selectの解説は第2回目)

使用方法のサンプルを次に示します。これによりプロンプトが出力され、入力を待ちます...5 秒経過しても入力がない場合、プログラムは終了します。入力がある場合、入力があるとすぐにそれを吐き戻して終了します...もちろん、これを独自の目的に合わせて変更することもできます。

def prompt
  STDOUT.write "> "
  STDOUT.flush
end

def amusing_messages
  [ "You must enter something!", 
    "Why did you even start me if you just wanted to stare at me?", 
    "Isn't there anything better you could be doing?", 
    "Just terminate me already... this is getting old",
    "I'm waiting..."]
end

prompt

loop do
  read_array, write_array, error_array = Kernel.select [STDIN], nil, nil, 5

  if read_array.nil?
    puts amusing_messages[rand(amusing_messages.length)]
  else
    puts "Result is: #{read_array[0].read_nonblock(30)}" 
  end

  prompt 

end

おそらくあなたが望むほどエレガントではありませんが、スレッドをいじることなく確実に仕事を完了します。残念ながら、これは、より堅牢なもの (タイマーやプロセスへのシグナル送信) が必要な場合には役に立ちません。また、悲しいことに、これが JRuby で機能するかどうかはわかりません。それがあるかどうか知りたいです:)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top