Skip to content

Instantly share code, notes, and snippets.

@domgetter
Created June 24, 2016 10:53
Show Gist options
  • Save domgetter/95b6f1372b9ec421f1523af4da175daa to your computer and use it in GitHub Desktop.
Save domgetter/95b6f1372b9ec421f1523af4da175daa to your computer and use it in GitHub Desktop.
class Thread
class TimeoutError < StandardError; end
def self.timeout(n)
temp_queue = Queue.new
work_thread = Thread.new { temp_queue << {return: yield} } # wrapping in a hash guarantees uniqueness of output
timeout_thread = Thread.new { sleep n; temp_queue << :timeout }
if (ret_val = temp_queue.pop) == :timeout # this pop is blocking, so it either waits on the yield or the timeout
work_thread.kill
raise TimeoutError
else
timeout_thread.kill
return ret_val[:return]
end
end
end
# This will either return "some val" or raise a Thread::Timeout
# Is raising an error a good idea? I don't know. The other
# options were to return nil or return a special Timeout object
# but I didn't like either of those, so I went with an error.
# It's not much trouble to wrap this in a begin, and it
# can be "dangerous", so I figured throwing an error was best.
Thread.timeout(1) do
sleep rand*2 # simulate work that takes 0 to 2 seconds
"some val"
end
# It actually feels pretty intuitive.
begin
Thread.timeout(2) do
(1..10000000000).reduce(:+)
end
rescue Thread::TimeoutError
puts "operation took longer than 2 seconds"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment