Newbie: Thread variables in Ruby Threads

Take the following piece of code:

···

------------------------------------------------------
count = 0
arr = []
10.times do |i|
  arr[i] = Thread.new {

    sleep(1)
    Thread.current["mycount"] = count
    count += 1
  }
end
arr.each {|t| t.join; print t["mycount"], ", " }
puts "count = #{count}"
------------------------------------------------------
It produces the following output:

9, 8, 7, 6, 5, 4, 3, 2, 1, 0, count = 10

I dont understand how it does this. This is what I would have expected
the output to have been as a result of each iteration of the #times
loop.

arr[0] count 0
arr[1] count 1
..
arr[9] count 9

so that when it reaches the line starting arr.each it would produce the
output

0, 1, 2, 3, 4, 5, 6, 7, 8, 9 count = 10; which is obviously the reverse
of what was actually printed. What am I missing here?

Thanxs in advance.

--
Posted via http://www.ruby-forum.com/.

It's not consistent. In my case, running your program I got

8, 7, 6, 5, 4, 3, 2, 1, 0, 9, count = 10

The thing is: you create 10 threads in quick succession. They all sleep
for 10 seconds. Suddenly they all start waking up, storing the current
value of count and incrementing it.

You can't predict what order they'll all wake up in. If you change
10.times to 100.times this might be clearer.

Alternatively, try changing sleep(1) to sleep(0.1*i) and it will be a
lot more predictable (although not entirely guaranteed).

However, the problems are worse than that. You might not even end up
with count=10 at the end! This is because the operation

  count += 1

is not atomic. It is really count = count + 1, which translates as
1. read the current value of count into a register
2. add 1 to the value in the register
3. write the register back to count

Let's say count=5 at some point in time, and two threads are ready to
run.

The first does step 1, reading value 5, and then is pre-empted by the
second thread. The second thread reads value 5, and writes value 6. The
first thread then wakes up and carries on. It also calculates 6 and
writes this to count.

So you need to protect the read-update-write operation with a mutex.

···

--
Posted via http://www.ruby-forum.com/.