Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > question on threads

Reply
Thread Tools

question on threads

 
 
Jean G.
Guest
Posts: n/a
 
      03-09-2010
Hello,

count = 0
threads = []

10.times do |i|
threads[i] = Thread.new do
sleep(rand(0.1))
Thread.current["mycount"] = count
count += 1
end
end

threads.each {|t| t.join; print t["mycount"], ", " }


For the code above, why the output numbers are random, rather than
from 0 to 9 by increasing?

Thanks.

 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      03-09-2010
2010/3/9 Jean G. <(E-Mail Removed)>:
> Hello,
>
> count =3D 0
> threads =3D []
>
> 10.times do |i|
> =A0threads[i] =3D Thread.new do
> =A0 =A0sleep(rand(0.1))
> =A0 =A0Thread.current["mycount"] =3D count
> =A0 =A0count +=3D 1
> =A0end
> end
>
> threads.each {|t| t.join; print t["mycount"], ", " }
>
>
> For the code above, why the output numbers are random, rather than
> from 0 to 9 by increasing?


Because there are no guarantees about thread scheduling. Btw, your
code is not really thread safe since you access a shared resource
without proper synchronization (although it might work on some Ruby
platforms).

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

 
Reply With Quote
 
 
 
 
Brian Candler
Guest
Posts: n/a
 
      03-09-2010
Jean G. wrote:
> Hello,
>
> count = 0
> threads = []
>
> 10.times do |i|
> threads[i] = Thread.new do
> sleep(rand(0.1))
> Thread.current["mycount"] = count
> count += 1
> end
> end
>
> threads.each {|t| t.join; print t["mycount"], ", " }
>
>
> For the code above, why the output numbers are random, rather than
> from 0 to 9 by increasing?


Because:

(1) each thread sleeps for a random amount of time before capturing and
incrementing the value of 'count'; but

(2) you join each thread in the order in which they were started.

Consider, for example, that threads[0] might sleep for 0.09 seconds, but
threads[1] might sleep for 0.02 seconds. Hence threads[1] will capture a
lower value than threads[0].

As has already been pointed out, this code is not threadsafe -
occasionally, two threads may capture the same value of 'count'. That's
because

count += 1

is really a shorthand for

count = count + 1

which is basically:
- read value of count
- add one to this value
- store this value back to count

Thread X could get as far as reading the value of 'count' before it is
suspended; then thread Y could run, read the same value of 'count', and
increment it. Then thread X will be re-scheduled, and also increment and
save back the same value.
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      03-10-2010
2010/3/9 Brian Candler <(E-Mail Removed)>:
> Jean G. wrote:
>> Hello,
>>
>> count =3D 0
>> threads =3D []
>>
>> 10.times do |i|
>> =A0 threads[i] =3D Thread.new do
>> =A0 =A0 sleep(rand(0.1))
>> =A0 =A0 Thread.current["mycount"] =3D count
>> =A0 =A0 count +=3D 1
>> =A0 end
>> end
>>
>> threads.each {|t| t.join; print t["mycount"], ", " }
>>
>>
>> For the code above, why the output numbers are random, rather than
>> from 0 to 9 by increasing?

>
> Because:
>
> (1) each thread sleeps for a random amount of time before capturing and
> incrementing the value of 'count'; but
>
> (2) you join each thread in the order in which they were started.
>
> Consider, for example, that threads[0] might sleep for 0.09 seconds, but
> threads[1] might sleep for 0.02 seconds. Hence threads[1] will capture a
> lower value than threads[0].
>
> As has already been pointed out, this code is not threadsafe -
> occasionally, two threads may capture the same value of 'count'. That's
> because
>
> =A0count +=3D 1
>
> is really a shorthand for
>
> =A0count =3D count + 1
>
> which is basically:
> =A0- read value of count
> =A0- add one to this value
> =A0- store this value back to count
>
> Thread X could get as far as reading the value of 'count' before it is
> suspended; then thread Y could run, read the same value of 'count', and
> increment it. Then thread X will be re-scheduled, and also increment and
> save back the same value.


Brian, thank you for taking the time to do a more elaborate explanation.

One additional thing: since Ruby's threads can actually return a value
we can rewrite the original piece to this version, which is also
thread safe:

lock =3D Mutex.new
count =3D 0

threads =3D (1..10).map do |i|
Thread.new do
sleep(rand(0.1))

lock.synchronize do
count +=3D 1
end
end
end

threads.each do |th|
puts th.value
end

Note that #synchronize returns the value returned by the block and by
that way we return the result of incrementing as the thread's return
value which is captured through Thread#value (which also joins the
thread).

Kind regards

robert


PS: We can make this even shorter, just for the fun of it - I don't
really recommend that style:

lock =3D Mutex.new
count =3D 0

(1..10).map do |i|
Thread.new do
sleep(rand(0.1))

lock.synchronize do
count +=3D 1
end
end
end.each do |th|
puts th.value
end


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Java Threads - Get running threads Pedro Pinto Java 2 04-08-2008 11:44 PM
[new to threads] threads with UI and loop Une bévue Ruby 0 06-14-2006 10:22 AM
TB View, Threads, Threads with unread The Invisible Man Firefox 1 03-20-2006 02:09 AM
Standard Threads vs Weightless Threads yoda Python 2 08-01-2005 09:12 PM
threads without threads sindica@gmail.com C Programming 4 08-27-2004 09:25 PM



Advertisments