Hi all
I am porting a timer class that I wrote in Java many years ago but I
cannot see how to implement it in Ruby.
What I want is a single thread, that sleeps forever or until the next
timer block should be called or until a new timer block i added.
The thread should be woken when a new timer block is added because it
might be the next one to be called.
I have implemented it like this:
#!/usr/bin/ruby
require ‘thread’
require ‘bsearch’
class Timer
class TimerObject
attr_reader :invoke_time, :block
def initialize(invoke_time, block)
@invoke_time, @block = invoke_time, block
end
end
def initialize
@timer_list = []
@mutex = Mutex.new
@condition = ConditionVariable.new
@running = false
start
end
def stop
running = false
@mutex.synchronize { @condition.signal }
end
def start
@running = true
Thread.new do
@mutex.synchronize do
an_hour = 60 * 60 * 1000
while running
now_in_milliseconds = (Time.now.to_f * 1000).to_i
milliseconds_to_sleep = @timer_list.empty? ? an_hour
: @timer_list.first.invoke_time - now_in_milliseconds
@condition.wait(@mutex, now_in_milliseconds) while
@timer_list.empty?
now_in_milliseconds = (Time.now.to_f * 1000).to_i
while @time_list.empty? == false and
@time_list.first.invoke_time < now_in_milliseconds
@time_list.delete_at(0).block.call
end
end
end
end
end
def postpone (timeout, &block)
now = (Time.now.to_f * 1000).to_i
time = now + timeout
timerobject = TimerObject.new time, block
@mutex.synchronize do
idx = @timer_list.bsearch_lower_boundary { |x| x.invoke_time
<=> time }
@timer_list.insert(idx, timerobject) unless idx.nil?
@timer_list << timerobject if idx.nil?
@condition.signal
end
end
end
BUT…the ‘start’ method does not work since ‘ConditionVariable’ does
not have a ‘wait’ method that takes a maximum wait time in milliseconds
like we have in Java.
Any ideas as to how this can be done ?
Or is there a better way ?
I really don’t want a thread per timer.
Best regards,
Robert