From: spox Date: 2009-09-11T00:33:33+09:00 Subject: Re: Timer implementation On Thursday 10 September 2009 04:15:08 am Robert Larsen wrote: > 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 Hi Robert. I have a simple timer that I built awhile ago. It uses a single thread for timed events, and a thread pool for executing blocks. If you are looking to build your own, the source can probably help give you some ideas. Project: http://rubyforge.org/projects/actiontimer Source: http://github.com/spox/actiontimer - spox