Skip to content

Instantly share code, notes, and snippets.

@ileitch
Created December 11, 2011 11:08
Show Gist options
  • Save ileitch/1459987 to your computer and use it in GitHub Desktop.
Save ileitch/1459987 to your computer and use it in GitHub Desktop.
Interruptible sleep in Ruby
module InterruptibleSleep
def interruptible_sleep(seconds)
@_sleep_check, @_sleep_interrupt = IO.pipe
IO.select([@_sleep_check], nil, nil, seconds)
end
def interrupt_sleep
@_sleep_interrupt.close if @_sleep_interrupt
end
end
class Test
include InterruptibleSleep
def start
puts "start"
interruptible_sleep 10
puts "sleep interrupted!"
end
def stop
puts "stop"
interrupt_sleep
end
end
test = Test.new
Signal.trap('SIGINT') { test.stop }
test.start
@aaronjensen
Copy link

aaronjensen commented Feb 6, 2018

Fwiw, the pattern here with the IO pipes appears to break on macs when they wake up from sleep. I don't know what causes it, but the app will get stuck reading from the pipe indefinitely and need to be killed. This is a different way of accomplishing the same thing that does not use pipes:

class InterruptibleSleeper
  def sleep(seconds)
    @sleeper = Thread.current
    Kernel.sleep seconds
  end

  def interrupt_sleep
    Thread.new { @sleeper&.run }
  end
end

This assumes that the thread that started the sleeping is still alive always, but additional safeguards could be put in place if that's an iffy thing.

This relies on the fact that Thread#run wakes threads up from sleep if another thread tells them to run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment