7

Why the result is not from 1 to 10, but 10s only?

require 'thread'

def run(i)
  puts i
end

while true
  for i in 0..10
    Thread.new{ run(i)}
  end
  sleep(100)
end

Result:

10
10
10
10
10
10
10
10
10
10
10

Why loop? I am running while loop, because later I want to iterate through the DB table all the time and echo any records that are retrieved from the DB.

2
  • Actually I ran your code on my machine and got some 3s and some 10s. Commented Jul 11, 2014 at 22:03
  • 2
    @DavidGrayson it is unpredictable what you will get here. You don't have guarantee for Thread context switching. So you could get many variants of result depending on the Moon phase. Commented Jul 11, 2014 at 22:10

3 Answers 3

11

The block that is passed to Thread.new may actually begin at some point in the future, and by that time the value of i may have changed. In your case, they all have incremented up to 10 prior to when all the threads actually run.

To fix this, use the form of Thread.new that accepts a parameter, in addition to the block:

require 'thread'

def run(i)
  puts i
end

while true
  for i in 0..10
    Thread.new(i) { |j| run(j) }
  end
  sleep(100)
end

This sets the block variable j to the value of i at the time new was called.

Sign up to request clarification or add additional context in comments.

1 Comment

Great! So now the second part :) stackoverflow.com/questions/24708758/…
2

@DavidGrayson is right.

You can see here a side effect in for loop. In your case i variable scope is whole your file. While you are expecting only a block in your for loop as a scope. Actually this is wrong approach in idiomatic Ruby. Ruby gives you iterators for this job.

(1..10).each do |i|
   Thread.new{ run(i)}
end

In this case scope of variable i will be isolated in block scope what means for each iteration you will get new local (for this block) variable i.

Comments

2

The problem is that you have created 11 threads that are all trying to access the same variable i which was defined by the main thread of your program. One trick to avoid that is to call Thread.new inside a method; then the variable i that the thread has access to is just the particular i that was passed to the method, and it is not shared with other threads. This takes advantage of a closure.

require 'thread'

def run(i)
  puts i
end

def start_thread(i)
  Thread.new { run i }
end

for i in 0..10
  start_thread i
  sleep 0.1
end

Result:

0
1
2
3
4
5
6
7
8
9
10

(I added the sleep just to guarantee that the threads run in numerical order so we can have tidy output, but you could take it out and still have a valid program where each thread gets the correct argument.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.