1

我正在寻找alarm(2)Ruby 中 POSIX(或类似)的可移植接口。也就是说,我希望能够设置一个后台计时器,在n秒后向当前进程发送信号。

我从 2006 年的 ruby​​-talk 列表中找到了一些很好的讨论,该列表提供了一个使用dl/import.

我已经查看了这个备受诟病的Timeout模块,尽管它在传统解释器中运行良好,但它不会在 JRuby 下削减它。我的程序是一个使用 Readline 库的小型命令行 shell:

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 返回预期的“未处理异常”错误。

4

1 回答 1

3

很抱歉,对于您在 X 秒后向进程发送信号的更大问题,我没有答案,但似乎您想要做的只是在等待输入 X 秒后超时,如果这是案例然后我会说你正在寻找 Kernel.select :D

我个人从来没有使用过这个,但是在为“非阻塞获取”做了一个谷歌之后,然后探索了链接,我发现这两个是非常宝贵的讨论:

http://www.ruby-forum.com/topic/126795(讨论多线程gets)

http://www.ruby-forum.com/topic/121404(第二篇文章中对 Kernel.select 的解释)

这是如何使用它的示例。这将打印出您的提示并等待输入...如果五秒钟后没有输入,则程序将结束。如果有输入,只要有输入,它就会将其吐出并结束……显然,您可以出于自己的目的对其进行修改。

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。很想知道它是否确实如此:)

于 2009-02-02T00:05:50.630 回答