# Thread.rb

**URL:** <https://rubytalk.org/t/thread-rb/45386>\
**Category:** ruby-talk\
**Created:** [25 March 2008 03:32 UTC](https://rubytalk.org/t/thread-rb/45386 "2008-03-25T03:32:38Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Adam\_Bender](https://avatars.discourse-cdn.com/v4/letter/a/df705f/32.png) [@Adam\_Bender](https://rubytalk.org/u/Adam_Bender)\
**Post date:** [25 March 2008 03:32 UTC](https://rubytalk.org/t/thread-rb/45386/1 "2008-03-25T03:32:38Z")

</div>

I want to modify the Queue class in thread.rb, so I first searched for  
the file. I found it in /usr/lib/ruby/1.8/thread.rb, both on a Mac  
and a Linux machine. On the Mac, the file was as expected, but on the  
Linux machine, it contained only this:

> **···**
>
> -----------------------  
> unless defined? Thread  
> &nbsp;&nbsp;fail "Thread not available for this ruby interpreter"  
> end
> 
> require '[thread.so](http://thread.so)'  
> -----------------------  
> Does this mean the Ruby code for Queue is compiled into a shared  
> library? Is it possible to edit the code? (I know I can modify the  
> class from outside the file, and that is probably what I will end up  
> doing, but I'm rather surprised by the above file contents and would  
> like to know more about it).
> 
> Thanks,
> 
> Adam
> 
> P.S. On a related note, I want to add a method to the Queue class that  
> is similar to pop, but will take a timeout value and return nil if it  
> no item is push'ed before timeout seconds have elapsed. Can anyone  
> suggest something better than the following:
> 
> class Queue  
> &nbsp;&nbsp;def pop\_with\_timeout(timeout)  
> &nbsp;&nbsp;&nbsp;&nbsp;elapsed = 0.0  
> &nbsp;&nbsp;&nbsp;&nbsp;while (Thread.critical = true; @que.empty?)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@waiting.push Thread.current  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.critical = false  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elapsed += sleep(timeout - elapsed)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts elapsed  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil if elapsed \>= timeout  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;&nbsp;@que.shift  
> &nbsp;&nbsp;ensure  
> &nbsp;&nbsp;&nbsp;&nbsp;Thread.critical = false  
> &nbsp;&nbsp;end  
> end
> 
> That was the first thing I came up with, and I'm (again) surprised  
> that it works - why does sleep ever return less than 1? What  
> interrupts it?

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [25 March 2008 11:57 UTC](https://rubytalk.org/t/thread-rb/45386/2 "2008-03-25T11:57:48Z")

</div>

> I want to modify the Queue class in thread.rb, so I first searched for

Why?

> P.S. On a related note, I want to add a method to the Queue class that  
> is similar to pop, but will take a timeout value and return nil if it  
> no item is push'ed before timeout seconds have elapsed. Can anyone  
> suggest something better than the following:
> 
> class Queue  
> &nbsp;&nbsp;def pop\_with\_timeout(timeout)  
> &nbsp;&nbsp;&nbsp;&nbsp;elapsed = 0.0  
> &nbsp;&nbsp;&nbsp;&nbsp;while (Thread.critical = true; @que.empty?)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@waiting.push Thread.current  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.critical = false  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elapsed += sleep(timeout - elapsed)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts elapsed  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil if elapsed \>= timeout  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;&nbsp;@que.shift  
> &nbsp;&nbsp;ensure  
> &nbsp;&nbsp;&nbsp;&nbsp;Thread.critical = false  
> &nbsp;&nbsp;end  
> end
> 
> That was the first thing I came up with, and I'm (again) surprised  
> that it works - why does sleep ever return less than 1? What  
> interrupts it?

I opt against using Thread.critical because this is a global exclusive  
lock on all threads and it is unlikely to continue to exist in the  
light of JRuby and others. I'd rather use Mutex#try\_lock or Monitor's  
#wait with timeout parameter.

Kind regards

robert

> **···**
>
> 2008/3/25, Adam Bender \<abender@gmail.com\>:
> 
> --  
> use.inject do |as, often| as.you\_can - without end

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [25 March 2008 18:01 UTC](https://rubytalk.org/t/thread-rb/45386/3 "2008-03-25T18:01:27Z")

</div>

Yes, it's implemented in C. In JRuby, it's implemented in Java.

I do agree that the following thread.rb operations need to directly  
support timeouts, though:

ConditionVariable#wait  
Queue#pop  
SizedQueue#pop  
SizedQueue#push

Unfortunately, there is no \_reliable\_ way to patch timeouts in after  
the fact. The support needs to be added to Ruby core.

In the interim, I think the best you can do is to implement your own  
queue data structure which supports timeouts using Mutex,  
ConditionVariable and the 'scheduler' gem. For instance:

require 'thread'  
require 'scheduler'

class MyQueue  
&nbsp;&nbsp;&nbsp;def initialize  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@lock = Mutex.new  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values =   
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@readers =   
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;class Timeout \< Interrupt  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;class Reader  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition = ConditionVariable.new  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@state = :waiting  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@value = nil  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def timeout  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@state = :timeout  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.signal  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def value=(value)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@value = value  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@state = :ready  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.signal  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def wait\_for\_value(lock)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@condition.wait(lock) while @state == :waiting  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise Timeout, "timed out" unless @state == :ready  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@value  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def push(value)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@lock.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if @readers.empty?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values.push value  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@readers.pop.value = value  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def pop(timeout=nil)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@lock.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unless @values.empty?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values.pop  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader = Reader.new  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@readers.push reader  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if timeout  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout = Scheduler.after\_delay!(timeout) do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@lock.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader.timeout if @readers.delete reader  
&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;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader.wait\_for\_value(@lock)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finally  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@readers.delete reader  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout.cancel if timeout  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end  
end

(This is untested, but should basically do what you need and you're  
welcome to use it. Feel free to ask any questions you might have.)

-mental

> **···**
>
> On Tue, 25 Mar 2008 12:32:38 +0900, "Adam Bender" \<abender@gmail.com\> wrote:
> 
> > require 'thread.so'  
> > -----------------------  
> > Does this mean the Ruby code for Queue is compiled into a shared  
> > library? Is it possible to edit the code? (I know I can modify the  
> > class from outside the file, and that is probably what I will end up  
> > doing, but I'm rather surprised by the above file contents and would  
> > like to know more about it).

---

<div class="post-metadata">

**Author:** ![Adam\_Bender](https://avatars.discourse-cdn.com/v4/letter/a/df705f/32.png) [@Adam\_Bender](https://rubytalk.org/u/Adam_Bender)\
**Post date:** [25 March 2008 17:04 UTC](https://rubytalk.org/t/thread-rb/45386/4 "2008-03-25T17:04:43Z")

</div>

> \> I want to modify the Queue class in thread.rb, so I first searched for
> 
> Why?

What what? I want to modify the class as described below; I searched  
for the file so I could see how pop was implemented and the class  
variables it used.

> \> P.S. On a related note, I want to add a method to the Queue class that  
> \> is similar to pop, but will take a timeout value and return nil if it  
> \> no item is push'ed before timeout seconds have elapsed. Can anyone  
> \> suggest something better than the following:  
> \>  
> \> class Queue  
> \> def pop\_with\_timeout(timeout)  
> \> elapsed = 0.0  
> \> while (Thread.critical = true; @que.empty?)  
> \> @waiting.push Thread.current  
> \> Thread.critical = false  
> \> elapsed += sleep(timeout - elapsed)  
> \> puts elapsed  
> \> return nil if elapsed \>= timeout  
> \> end  
> \> @que.shift  
> \> ensure  
> \> Thread.critical = false  
> \> end  
> \> end  
> \>  
> \> That was the first thing I came up with, and I'm (again) surprised  
> \> that it works - why does sleep ever return less than 1? What  
> \> interrupts it?
> 
> I opt against using Thread.critical because this is a global exclusive  
> lock on all threads and it is unlikely to continue to exist in the  
> light of JRuby and others. I'd rather use Mutex#try\_lock or Monitor's  
> #wait with timeout parameter.

The Queue class uses Thread.critical. Though I guess writing a queue  
using a Monitor would be easy enough to do.

Adam

> **···**
>
> On Tue, Mar 25, 2008 at 7:57 AM, Robert Klemme \<shortcutter@googlemail.com\> wrote:
> 
> > 2008/3/25, Adam Bender \<abender@gmail.com\>:

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [25 March 2008 18:11 UTC](https://rubytalk.org/t/thread-rb/45386/5 "2008-03-25T18:11:55Z")

</div>

Agreed, anything using Thread.critical is not very future-proof.

Note, however, that while Monitor is okay under JRuby, in MRI (1.9 at least)  
it uses Timeout in an uncontrolled way and is not entirely reliable as a  
result. To implement Monitor robustly in JRuby we ended up adding timeout  
support to JRuby's ConditionVariable#wait.

\*\*\* I would strongly recommend \_against\_ using any concurrency primitive in  
1.9 except for the primitives from thread.rb/thread.so. \*\*\*

Given that, the most directly portable way to get a robust queue that  
supports timeouts is to roll your own using Mutex, ConditionVariable, and  
some safe source of timed events like Scheduler.

-mental

> **···**
>
> On Tue, 25 Mar 2008 20:57:48 +0900, "Robert Klemme" \<shortcutter@googlemail.com\> wrote:
> 
> > I opt against using Thread.critical because this is a global exclusive  
> > lock on all threads and it is unlikely to continue to exist in the  
> > light of JRuby and others. I'd rather use Mutex#try\_lock or Monitor's  
> > #wait with timeout parameter.

---

<div class="post-metadata">

**Author:** ![Adam\_Bender](https://avatars.discourse-cdn.com/v4/letter/a/df705f/32.png) [@Adam\_Bender](https://rubytalk.org/u/Adam_Bender)\
**Post date:** [25 March 2008 22:32 UTC](https://rubytalk.org/t/thread-rb/45386/6 "2008-03-25T22:32:27Z")

</div>

ConditionVariable#wait appears to support timeouts  
([http://www.ruby-doc.org/stdlib/libdoc/monitor/rdoc/classes/MonitorMixin/ConditionVariable.html#M001018\](http://www.ruby-doc.org/stdlib/libdoc/monitor/rdoc/classes/MonitorMixin/ConditionVariable.html#M001018%5C)).  
Do they not work as expected?

I couldn't find the Scheduler gem, so I'm trying to hack something  
together based your code example, but using Monitors. It depends on  
ConditionVariable#wait, so it could be totally broken. I didn't  
understand the point of the Reader class in your code, since only one  
thread at a time can acquire the lock in pop. This problem is closely  
related to the example on page 146 of Pickaxe 2nd ed.

require 'monitor'

class MyQueue

&nbsp;&nbsp;def initialize  
&nbsp;&nbsp;&nbsp;&nbsp;@values =   
&nbsp;&nbsp;&nbsp;&nbsp;@values.extend(MonitorMixin)  
&nbsp;&nbsp;&nbsp;&nbsp;@cond = @values.new\_cond  
&nbsp;&nbsp;end

&nbsp;&nbsp;def push(value)  
&nbsp;&nbsp;&nbsp;&nbsp;@values.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values.push value  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@cond.signal  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;self  
&nbsp;&nbsp;end

&nbsp;&nbsp;def pop(timeout=nil)  
&nbsp;&nbsp;&nbsp;&nbsp;ret = nil  
&nbsp;&nbsp;&nbsp;&nbsp;@values.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t = Time.now  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@cond.wait(timeout)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "waited #{Time.now - t}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = @values.shift unless @values.empty?  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;return ret  
&nbsp;&nbsp;end  
end

q = MyQueue.new

consumers = (1..3).map do |i|  
&nbsp;&nbsp;Thread.new("consumer #{i}") do |name|  
&nbsp;&nbsp;&nbsp;&nbsp;begin  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj = q.pop(5)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "#{name} consumed #{obj.inspect}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(rand(0.05))  
&nbsp;&nbsp;&nbsp;&nbsp;end until obj == :END\_OF\_WORK  
&nbsp;&nbsp;end  
end

producers = (1..3).map do |i|  
&nbsp;&nbsp;Thread.new("producer #{i}") do |name|  
&nbsp;&nbsp;&nbsp;&nbsp;3.times do |j|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q.push("Item #{j} from #{name}")  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end

producers.each { |th| th.join }  
consumers.size.times { q.push(:END\_OF\_WORK) }  
consumers.each { |th| th.join }

The problem is that the wait() waits for timeout seconds, even when  
something is in the queue.

Thanks for your help,

Adam

> **···**
>
> On Tue, Mar 25, 2008 at 2:01 PM, MenTaLguY \<mental@rydia.net\> wrote:
> 
> > I do agree that the following thread.rb operations need to directly  
> > support timeouts, though:
> > 
> > &nbsp;&nbsp;ConditionVariable#wait

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [25 March 2008 18:31 UTC](https://rubytalk.org/t/thread-rb/45386/7 "2008-03-25T18:31:44Z")

</div>

> Note, however, that while Monitor is okay under JRuby, in MRI (1.9 at  
> least) it uses Timeout in an uncontrolled way and is not entirely reliable  
> as a result.

I am wrong. Timeouts are currently unimplemented in 1.9's Monitor.

> \*\*\* I would strongly recommend \_against\_ using any concurrency primitive  
> in 1.9 except for the primitives from thread.rb/thread.so. \*\*\*

Evidently more things have changed since 1.8 than I had thought, so  
this may or may not still hold.

-mental

> **···**
>
> On Wed, 26 Mar 2008 03:11:55 +0900, MenTaLguY \<mental@rydia.net\> wrote:

---

<div class="post-metadata">

**Author:** ![Adam\_Bender](https://avatars.discourse-cdn.com/v4/letter/a/df705f/32.png) [@Adam\_Bender](https://rubytalk.org/u/Adam_Bender)\
**Post date:** [25 March 2008 22:37 UTC](https://rubytalk.org/t/thread-rb/45386/8 "2008-03-25T22:37:32Z")

</div>

My apologies, I didn't read your previous replies thoroughly enough.  
Anyways, I'm not worried about 1.9 portability just yet, I just need  
something that works in 1.8.6.

Thanks again,

Adam

> **···**
>
> On Tue, Mar 25, 2008 at 6:31 PM, Adam Bender \<abender@gmail.com\> wrote:
> 
> > On Tue, Mar 25, 2008 at 2:01 PM, MenTaLguY \<mental@rydia.net\> wrote:  
> > \> I do agree that the following thread.rb operations need to directly  
> > \> support timeouts, though:  
> > \>  
> > \> ConditionVariable#wait
> > 
> > ConditionVariable#wait appears to support timeouts  
> > ([http://www.ruby-doc.org/stdlib/libdoc/monitor/rdoc/classes/MonitorMixin/ConditionVariable.html#M001018\](http://www.ruby-doc.org/stdlib/libdoc/monitor/rdoc/classes/MonitorMixin/ConditionVariable.html#M001018%5C)).  
> > &nbsp;&nbsp;Do they not work as expected?

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [26 March 2008 00:06 UTC](https://rubytalk.org/t/thread-rb/45386/9 "2008-03-26T00:06:02Z")

</div>

> I couldn't find the Scheduler gem

gem install scheduler

> I didn't understand the point of the Reader class in your code, since  
> only one thread at a time can acquire the lock in pop.

The lock is released (by ConditionVariable#wait) while a reader is  
waiting (and re-acquired before ConditionVariable#wait returns).  
Otherwise writers couldn't get in to write.

Conceptually, a Queue is actually two queues: a queue of "pushes" which  
holds pushed values, and a queue of "pops" which holds threads waiting  
for new values to be pushed.

If there have been more pushes than pops, the "pushes" queue will have  
entries in it, and if there have been more pops than pushes, the "pops"  
queue will have entries in it. Each push tries to take an entry from  
the "pops" queue and vice-versa, so that when there have been an equal  
number of pushes and pops, both queues will be empty.

Readers are just used to represent entries in the "pops" queue.

-mental

> **···**
>
> On Wed, 26 Mar 2008 07:32:27 +0900, "Adam Bender" \<abender@gmail.com\> wrote:

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [26 March 2008 00:09 UTC](https://rubytalk.org/t/thread-rb/45386/10 "2008-03-26T00:09:51Z")

</div>

In this case, the problem is that you are always putting the thread to  
sleep on the "pops" queue, even when there is already a pushed value  
available on the "pushes" queue.

You need to check whether the "pushes" queue is empty and only sleep  
when it is:

def pop  
&nbsp;&nbsp;&nbsp;@values.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while @values.empty?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@cond.wait  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values.shift  
&nbsp;&nbsp;&nbsp;end  
end

Note that I've used a while loop rather than a simple if test; this is  
for several reasons, but mainly because it is possible for another  
thread to "steal" a value from the "pops" queue before we finish  
waking up. Because of that, we have to check the predicate again after  
@cond.wait returns, and potentially go back to sleep.

Implementing this in conjunction with timeout is harder, but possible:

def pop(timeout = nil)  
&nbsp;&nbsp;&nbsp;if timeout  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deadline = Time.now + timeout  
&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deadline = nil  
&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;@values.synchronize do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while @values.empty?  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if deadline  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout = deadline - Time.now  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return nil if timeout \<= 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@cond.wait(timeout)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values.shift  
&nbsp;&nbsp;&nbsp;end  
end

Since this uses the system clock rather than a monotonic timer, it does  
still have a bug inasmuch as changing the system time can cause #pop to  
wait for too long or too little, but Ruby 1.8 and 1.9 have that same bug  
in their thread schedulers anyway.

-mental

> **···**
>
> On Wed, 26 Mar 2008 07:32:27 +0900, "Adam Bender" \<abender@gmail.com\> wrote:
> 
> > &nbsp;&nbsp;def push(value)  
> > &nbsp;&nbsp;&nbsp;&nbsp;@values.synchronize do  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@values.push value  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@cond.signal  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;self  
> > &nbsp;&nbsp;end
> > 
> > &nbsp;&nbsp;def pop(timeout=nil)  
> > &nbsp;&nbsp;&nbsp;&nbsp;ret = nil  
> > &nbsp;&nbsp;&nbsp;&nbsp;@values.synchronize do  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t = Time.now  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@cond.wait(timeout)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "waited #{Time.now - t}"  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret = @values.shift unless @values.empty?  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;return ret  
> > &nbsp;&nbsp;end
> 
> > The problem is that the wait() waits for timeout seconds, even when  
> > something is in the queue.

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [26 March 2008 00:13 UTC](https://rubytalk.org/t/thread-rb/45386/11 "2008-03-26T00:13:13Z")

</div>

Monitor should work then, although the implementation of timeouts is  
a little flaky in 1.8. It should work reliably in JRuby though.

-mental

> **···**
>
> On Wed, 26 Mar 2008 07:37:32 +0900, "Adam Bender" \<abender@gmail.com\> wrote:
> 
> > My apologies, I didn't read your previous replies thoroughly enough.  
> > Anyways, I'm not worried about 1.9 portability just yet, I just need  
> > something that works in 1.8.6.

---

<div class="post-metadata">

**Author:** ![Adam\_Bender](https://avatars.discourse-cdn.com/v4/letter/a/df705f/32.png) [@Adam\_Bender](https://rubytalk.org/u/Adam_Bender)\
**Post date:** [26 March 2008 03:50 UTC](https://rubytalk.org/t/thread-rb/45386/12 "2008-03-26T03:50:08Z")

</div>

> \> I couldn't find the Scheduler gem
> 
> gem install scheduler

Hmm. That didn't work the first time I tried it (the gem wasn't  
found), but it worked just now.

> In this case, the problem is that you are always putting the thread to  
> sleep on the "pops" queue, even when there is already a pushed value  
> available on the "pushes" queue.

I realized later on that that was probably the problem, and indeed it was.

> Implementing this in conjunction with timeout is harder, but possible:

Awesome, this gives me exactly what I need. Thanks for you help.

Adam

> **···**
>
> On Tue, Mar 25, 2008 at 8:09 PM, MenTaLguY \<mental@rydia.net\> wrote:
> 
> > On Wed, 26 Mar 2008 07:32:27 +0900, "Adam Bender" \<abender@gmail.com\> wrote:
