# Timer implementation

**URL:** <https://rubytalk.org/t/timer-implementation/55324>\
**Category:** ruby-talk\
**Created:** [10 September 2009 11:15 UTC](https://rubytalk.org/t/timer-implementation/55324 "2009-09-10T11:15:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Robert\_Larsen](https://avatars.discourse-cdn.com/v4/letter/r/5e9695/32.png) [@Robert\_Larsen](https://rubytalk.org/u/Robert_Larsen)\
**Post date:** [10 September 2009 11:15 UTC](https://rubytalk.org/t/timer-implementation/55324/1 "2009-09-10T11:15:08Z")

</div>

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  
&nbsp;&nbsp;&nbsp;&nbsp;class TimerObject  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attr\_reader :invoke\_time, :block

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(invoke\_time, block)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@invoke\_time, @block = invoke\_time, block  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def initialize  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@timer\_list = []  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex = Mutex.new  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition = ConditionVariable.new  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running = false  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def stop  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running = false  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex.synchronize { @condition.signal }  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def start  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running = true  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.new do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an\_hour = 60 \* 60 \* 1000  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while running  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now\_in\_milliseconds = (Time.now.to\_f \* 1000).to\_i  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;milliseconds\_to\_sleep = @timer\_list.empty? ? an\_hour : @timer\_list.first.invoke\_time - now\_in\_milliseconds  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.wait(@mutex, now\_in\_milliseconds) while @timer\_list.empty?

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now\_in\_milliseconds = (Time.now.to\_f \* 1000).to\_i  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while @time\_list.empty? == false and @time\_list.first.invoke\_time \< now\_in\_milliseconds  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@time\_list.delete\_at(0).block.call  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;def postpone (timeout, &block)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now = (Time.now.to\_f \* 1000).to\_i  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time = now + timeout

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timerobject = TimerObject.new time, block

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idx = @timer\_list.bsearch\_lower\_boundary { |x| x.invoke\_time \<=\> time }  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@timer\_list.insert(idx, timerobject) unless idx.nil?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@timer\_list \<\< timerobject if idx.nil?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.signal  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;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

---

<div class="post-metadata">

**Author:** ![Robert\_Larsen](https://avatars.discourse-cdn.com/v4/letter/r/5e9695/32.png) [@Robert\_Larsen](https://rubytalk.org/u/Robert_Larsen)\
**Post date:** [10 September 2009 11:15 UTC](https://rubytalk.org/t/timer-implementation/55324/2 "2009-09-10T11:15:08Z")

</div>

Robert Larsen wrote:

> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.wait(@mutex, now\_in\_milliseconds) while @timer\_list.empty?

Whoops, the above should of course be:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.wait(@mutex, milliseconds\_to\_sleep)

---

<div class="post-metadata">

**Author:** ![Tanaka\_Akira](https://avatars.discourse-cdn.com/v4/letter/t/439d5e/32.png) [@Tanaka\_Akira](https://rubytalk.org/u/Tanaka_Akira)\
**Post date:** [10 September 2009 15:16 UTC](https://rubytalk.org/t/timer-implementation/55324/3 "2009-09-10T15:16:23Z")

</div>

In article \<4aa8deb2$0$25181$d40e179e@nntp02.dk.telia.net\>,  
&nbsp;&nbsp;Robert Larsen \<robert@komogvind.dk\> writes:

> 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.

In ruby 1.9, timeout argument can be implemented as follows.

Index: lib/thread.rb

> **···**
>
> ===================================================================  
> --- lib/thread.rb (revision 24783)  
> +++ lib/thread.rb (working copy)  
> @@ -59,13 +59,16 @@  
> &nbsp;&nbsp;&nbsp;#  
> &nbsp;&nbsp;&nbsp;# Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.  
> &nbsp;&nbsp;&nbsp;#  
> - def wait(mutex)  
> + # If +timeout+ is given, this method returns after +timeout+ seconds passed,  
> + # even if no other thread doesn't signal.  
> + #  
> + def wait(mutex, timeout=nil)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# TODO: mutex should not be used  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@waiters\_mutex.synchronize do  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@waiters.push(Thread.current)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> - mutex.sleep  
> + mutex.sleep timeout  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;end
> 
> --  
> Tanaka Akira

---

<div class="post-metadata">

**Author:** ![spox](https://avatars.discourse-cdn.com/v4/letter/s/ecc23a/32.png) [@spox](https://rubytalk.org/u/spox)\
**Post date:** [10 September 2009 15:33 UTC](https://rubytalk.org/t/timer-implementation/55324/4 "2009-09-10T15:33:33Z")

</div>

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](http://rubyforge.org/projects/actiontimer)

Source:

> **[GitHub - spox/actiontimer: Simple timer for a complex world](https://github.com/spox/actiontimer)**
>
> Simple timer for a complex world. Contribute to spox/actiontimer development by creating an account on GitHub.

- spox

> **···**
>
> 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  
> > &nbsp;&nbsp;&nbsp;&nbsp;class TimerObject  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;attr\_reader :invoke\_time, :block
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(invoke\_time, block)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@invoke\_time, @block = invoke\_time, block  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;def initialize  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@timer\_list =   
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex = Mutex.new  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition = ConditionVariable.new  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running = false  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start  
> > &nbsp;&nbsp;&nbsp;&nbsp;end
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;def stop  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;running = false  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex.synchronize { @condition.signal }  
> > &nbsp;&nbsp;&nbsp;&nbsp;end
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;def start  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running = true  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.new do  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex.synchronize do  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an\_hour = 60 \* 60 \* 1000  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while running  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now\_in\_milliseconds = (Time.now.to\_f \* 1000).to\_i  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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?
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now\_in\_milliseconds = (Time.now.to\_f \* 1000).to\_i  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while @time\_list.empty? == false and  
> > @time\_list.first.invoke\_time \< now\_in\_milliseconds  
> > @time\_list.delete\_at(0).block.call  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;def postpone (timeout, &block)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;now = (Time.now.to\_f \* 1000).to\_i  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;time = now + timeout
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timerobject = TimerObject.new time, block
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mutex.synchronize do  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idx = @timer\_list.bsearch\_lower\_boundary { |x| x.invoke\_time  
> > \<=\> time } @timer\_list.insert(idx, timerobject) unless idx.nil?  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@timer\_list \<\< timerobject if idx.nil?  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.signal  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;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
