문제

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

저는 개인적으로 이것을 사용한 적이 없지만 "비차단 가져오기"에 대해 Google을 검색한 후 링크를 ​​탐색한 후 다음 두 가지 토론이 매우 중요하다는 것을 알았습니다.

http://www.ruby-forum.com/topic/126795 (멀티스레드 가져오기에 대한 논의)

http://www.ruby-forum.com/topic/121404 (2번째 포스팅의 Kernel.select에 대한 설명)

사용 방법에 대한 샘플은 다음과 같습니다.그러면 프롬프트가 인쇄되고 입력을 기다립니다...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