Created
June 24, 2016 10:53
-
-
Save domgetter/95b6f1372b9ec421f1523af4da175daa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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