question on threads

Discussion in 'Ruby' started by Jean G., Mar 9, 2010.

  1. Jean G.

    Jean G. Guest

    Hello,

    count = 0
    threads = []

    10.times do |i|
    threads = 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.
    Jean G., Mar 9, 2010
    #1
    1. Advertising

  2. 2010/3/9 Jean G. <>:
    > Hello,
    >
    > count =3D 0
    > threads =3D []
    >
    > 10.times do |i|
    > =A0threads =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/
    Robert Klemme, Mar 9, 2010
    #2
    1. Advertising

  3. Jean G. wrote:
    > Hello,
    >
    > count = 0
    > threads = []
    >
    > 10.times do |i|
    > threads = 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/.
    Brian Candler, Mar 9, 2010
    #3
  4. 2010/3/9 Brian Candler <>:
    > Jean G. wrote:
    >> Hello,
    >>
    >> count =3D 0
    >> threads =3D []
    >>
    >> 10.times do |i|
    >> =A0 threads =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/
    Robert Klemme, Mar 10, 2010
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Nick Marden
    Replies:
    0
    Views:
    1,057
    Nick Marden
    Jan 17, 2004
  2. yoda
    Replies:
    2
    Views:
    420
    =?utf-8?Q?Bj=C3=B6rn_Lindstr=C3=B6m?=
    Aug 1, 2005
  3. threads without threads

    , Aug 27, 2004, in forum: C Programming
    Replies:
    4
    Views:
    384
    William Ahern
    Aug 27, 2004
  4. Pedro Pinto

    Java Threads - Get running threads

    Pedro Pinto, Apr 8, 2008, in forum: Java
    Replies:
    2
    Views:
    1,404
    Arne Vajhøj
    Apr 9, 2008
  5. Une bévue
    Replies:
    0
    Views:
    132
    Une bévue
    Jun 14, 2006
Loading...

Share This Page