2009-02-01 39 views
1

我正在寻找一个便携式接口到POSIX alarm(2)(或类似)在Ruby中。也就是说,我希望能够在 n秒之后设置后台计时器来发送信号到当前进程。异步报警信号

我从2006年的ruby-talk列表中发现了一些good discussion,它提供了一个使用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返回预期的“未处理的异常”错误。

回答

3

对不起,我没有回答你在X秒后发送信号到一个进程的大问题,但似乎你想要做的是在等待输入X秒后超时,如果是这样的话,那么我会说你正在寻找Kernel.select:D

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

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

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中有效,我不知道。想知道它是否通过:)

+0

+1为整洁的想法,但我想保持readline(命令行编辑,历史,完成,..)。我已经重写了我的一个类,所以我可以放弃JRuby。使用BouncyCastle进行快速原型设计是非常棒的,但JRuby对于认真的工作仍然很年轻(并且不会和我讨论关于Kernel#select docs !!)。干杯! – 2009-02-03 06:20:06