2009-02-01 41 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