# Multi Threading

**URL:** <https://www.ruby-forum.com/t/multi-threading/165765>\
**Category:** Ruby\
**Created:** [April 17, 2009, 7:44am UTC](https://www.ruby-forum.com/t/multi-threading/165765 "2009-04-17T07:44:55Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sriram](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/46a35a/32.png) [@sriram](https://www.ruby-forum.com/u/sriram)\
**Post date:** [April 17, 2009, 7:44am UTC](https://www.ruby-forum.com/t/multi-threading/165765/1 "2009-04-17T07:44:55Z")

</div>

Hello,

#\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*STARTCODE

start\_time = Time.now  
$count = 0  
class Queue  
def initialize \*s # splat operator allows variable length argument  
list  
@mutex = Mutex.new  
@queue = []  
s.each { |e| @queue.push e }  
end

def enq v  
@queue.push v  
end

def deq  
@mutex.synchronize {item = @queue.shift}  
end

def empty?  
@mutex.synchronize{@queue.length == 0}  
end

def count  
@mutex.synchronize do  
$count += 1  
end  
end  
end

#\*\*\*\*\*Test

queue = Queue.new  
500.times do |a|  
queue.enq a  
end  
threads = []

# Create 5 threads which fetch values from the Q.

5.times do  
threads \<\< Thread.new {  
until queue.empty?  
queue.count  
puts “Thread ID: #{Thread.current}.Job started”  
puts “#{queue.deq}”  
#sleep 0.0001  
puts “Thread ID: #{Thread.current}.Job complete”  
end  
}  
end

threads.each {|t| t.join }  
puts “Count”  
puts $count  
puts “timeTaken:”  
puts Time.now - start\_time

# _ **CODE ENDS** _\*\*\*\*\*

I have five threads which fetch values from a queue. The above code  
works perfectly well in case of a single thread. But the issue arises  
when there are more threads.

In case of 5 threads the number of times the block is executed is 503  
where it should have been 500.

I know the reason why?  
The “deq” and “empty?” methods are not synchronized.  
So when the final item is removed from the thread, other threads access  
the empty? method before the @queue.length becomes 0.

Hence the difference in count.

If the sleep is activated this problem is solved.

Any suggestion on how to get this working without the sleep?

Thanks.

---

<div class="post-metadata">

**Author:** ![sriram](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/46a35a/32.png) [@sriram](https://www.ruby-forum.com/u/sriram)\
**Post date:** [April 17, 2009, 8:23am UTC](https://www.ruby-forum.com/t/multi-threading/165765/2 "2009-04-17T08:23:23Z")

</div>

Sriram V. wrote:

> ```
> @queue = []
> 
> ```
> 
> # Create 5 threads which fetch values from the Q.
> 
> end
> 
> the empty? method before the @queue.length becomes 0.
> 
> Hence the difference in count.
> 
> If the sleep is activated this problem is solved.
> 
> Any suggestion on how to get this working without the sleep?

You should also synchronize the enque operation (Queue#enq). Btw, there  
is  
an existing Queue class that does this thread-safe:

require ‘thread’  
q = Queue.new  
q.push 1  
x = q.pop  
q.pop # =\> would block the thread until a new element is available

q2 = SizedQueue.new(10) # bounded queue, which blocks when size \> 10

Regards,

Michael

---

<div class="post-metadata">

**Author:** ![sriram](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/46a35a/32.png) [@sriram](https://www.ruby-forum.com/u/sriram)\
**Post date:** [April 17, 2009, 8:56am UTC](https://www.ruby-forum.com/t/multi-threading/165765/3 "2009-04-17T08:56:14Z")

</div>

2009/4/17 Sriram V. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> @queue = []
> 
> # Create 5 threads which fetch values from the Q.
> 
> end
> 
> the empty? method before the @queue.length becomes 0.
> 
> Hence the difference in count.
> 
> If the sleep is activated this problem is solved.
> 
> Any suggestion on how to get this working without the sleep?

There are several options. You could use MonitorMixin instead of Mutex  
and include it in initialize

def initialize \*s

# @mutex == self so you do not need to change sync code

@mutex = extend MonitorMixin  
@queue = s.dup  
end

Then you can do external synchronization, e.g.

queue.synchronize do  
if queue.empty?

# finish

else  
elm = deq  
end  
end

Much better though is this approach

require ‘thread’

# use library class

queue = Queue.new

# _first_ start threads

# does not really matter but if filling

# the queue takes time work can

# begin immediately

threads = (1…5).map do  
label = Thread.current.to\_s.freeze

Thread.new queue do |q|  
until ( job = q.deq ) == :terminate  
puts “Thread ID: #{label}.Job started”  
puts job  
puts “Thread ID: #{label}.Job complete”  
end  
end  
end

# fill queues

500.times do |a|  
queue.enq a  
end

# “close” queues

threads.size.times { queue.enq :terminate }

# wait for termination

threads.each do |th|  
th.join  
end

Cheers

robert

---

<div class="post-metadata">

**Author:** ![sriram](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/46a35a/32.png) [@sriram](https://www.ruby-forum.com/u/sriram)\
**Post date:** [April 17, 2009, 9:23am UTC](https://www.ruby-forum.com/t/multi-threading/165765/4 "2009-04-17T09:23:17Z")

</div>

On Fri, Apr 17, 2009 at 7:55 AM, Robert K.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> # the queue takes time work can
> 
> end
> 
> # wait for termination
> 
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

Minor nitpick - these lines should be reversed:

> label = Thread.current.to\_s.freeze  
> Thread.new queue do |q|

i.e.

> Thread.new queue do |q|  
> label = Thread.current.to\_s.freeze

Regards,  
Sean

---

<div class="post-metadata">

**Author:** ![sriram](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/46a35a/32.png) [@sriram](https://www.ruby-forum.com/u/sriram)\
**Post date:** [April 17, 2009, 9:43am UTC](https://www.ruby-forum.com/t/multi-threading/165765/5 "2009-04-17T09:43:21Z")

</div>

Hey Robert,

That was an amazing solution!Thanks a million 🙂

Thank you Michael and Sean for your time 🙂

---

<div class="post-metadata">

**Author:** ![sriram](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/46a35a/32.png) [@sriram](https://www.ruby-forum.com/u/sriram)\
**Post date:** [April 17, 2009, 10:02am UTC](https://www.ruby-forum.com/t/multi-threading/165765/6 "2009-04-17T10:02:34Z")

</div>

2009/4/17 Sean O’Halpin [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Minor nitpick - these lines should be reversed:
> 
> > label = Thread.current.to\_s.freeze  
> > Thread.new queue do |q|
> 
> i.e.
> 
> > Thread.new queue do |q|  
> > label = Thread.current.to\_s.freeze

Oh yes, absolutely! Apparently I moved the line too high. Thanks for  
catching that gotcha, Sean!

Kind regards

robert
