From: Nita Neou on
Hi All

I got a little problem when using thread function and variable, let's
say this code :

require 'rubygems'
require 'watir'
require 'thread'

def testfunc(id)
total = id + 5
puts "id #{id} is #{total}"
end

threads = []
numberlist = [1, 2, 3]
for id in numberlist
threads << Thread.new {testfunc(id)}
end

threads.each { |aThread| aThread.join }

my output is :
[sophoah(a)fedora ]$ ruby test.rb
id 3 is 8
id 3 is 8
id 3 is 8

The fact is that I would like this output :
id 1 is 6
id 2 is 7
id 3 is 8

I am suspecting that all variable id, and total are all share among
all the thread, is that right ? why ? I thought variable in a block
were not share among variable ? How can I fix this problem ?

Thanks a lot for your help on it,
Regards
Nita
From: Roger Pack on
> threads = []
> numberlist = [1, 2, 3]
> for id in numberlist
> threads << Thread.new {testfunc(id)}
> end

...

> The fact is that I would like this output :
> id 1 is 6
> id 2 is 7
> id 3 is 8

what's happening is that "id" is being changed as it iterates through
the numberlist.
So when each thread starts and finally gets around to running
"testfunc(id)" they all call it with the end value.

The fix is that you can pass a value "through" to the new threads, thus:

Thread.new(id) {|id| testfunc(id) }

Then it will preserve the original value.
-r
--
Posted via http://www.ruby-forum.com/.

From: Jesús Gabriel y Galán on
On Tue, Jul 6, 2010 at 6:00 PM, Nita Neou <sophoah(a)gmail.com> wrote:
> Hi All
>
> I got a little problem when using thread function and variable, let's
> say this code :
>
> require 'rubygems'
> require 'watir'
> require 'thread'
>
> def testfunc(id)
>        total = id + 5
>        puts "id #{id} is #{total}"
> end
>
> threads = []
> numberlist = [1, 2, 3]
> for id in numberlist
>        threads << Thread.new {testfunc(id)}
> end
>
> threads.each { |aThread|  aThread.join }
>
> my output is :
> [sophoah(a)fedora ]$ ruby test.rb
> id 3 is 8
> id 3 is 8
> id 3 is 8
>
> The fact is that I would like this output :
> id 1 is 6
> id 2 is 7
> id 3 is 8
>
> I am suspecting that all variable id, and total are all share among
> all the thread, is that right ? why ? I thought variable in a block
> were not share among variable ? How can I fix this problem ?

Blocks in Ruby are closures, this means that inside the block you pass
to Thread.new, the variable id is the same.
The Thread class has a way to avoid this, take a look at the constructor:

http://ruby-doc.org/core/classes/Thread.html#M000437

You can pass parameters to #new and it will pass them to the block.
You can use this technique to use a variable in the block that is
different for each thread, like this:

def testfunc(id)
total = id + 5
puts "id #{id} is #{total}"
end

threads = []
numberlist = [1, 2, 3]
for id in numberlist
threads << Thread.new(id) {|my_id| testfunc(my_id)}
end

threads.each { |aThread| aThread.join }


$ ruby threads.rb
id 1 is 6
id 2 is 7
id 3 is 8


Jesus.

From: Nita Neou on
On Jul 7, 12:15 am, Jesús Gabriel y Galán <jgabrielyga...(a)gmail.com>
wrote:
> On Tue, Jul 6, 2010 at 6:00 PM, Nita Neou <soph...(a)gmail.com> wrote:
> > Hi All
>
> > I got a little problem when using thread function and variable, let's
> > say this code :
>
> > require 'rubygems'
> > require 'watir'
> > require 'thread'
>
> > def testfunc(id)
> >        total = id + 5
> >        puts "id #{id} is #{total}"
> > end
>
> > threads = []
> > numberlist = [1, 2, 3]
> > for id in numberlist
> >        threads << Thread.new {testfunc(id)}
> > end
>
> > threads.each { |aThread|  aThread.join }
>
> > my output is :
> > [sophoah(a)fedora ]$ ruby test.rb
> > id 3 is 8
> > id 3 is 8
> > id 3 is 8
>
> > The fact is that I would like this output :
> > id 1 is 6
> > id 2 is 7
> > id 3 is 8
>
> > I am suspecting that all variable id, and total are all share among
> > all the thread, is that right ? why ? I thought variable in a block
> > were not share among variable ? How can I fix this problem ?
>
> Blocks in Ruby are closures, this means that inside the block you pass
> to Thread.new, the variable id is the same.
> The Thread class has a way to avoid this, take a look at the constructor:
>
> http://ruby-doc.org/core/classes/Thread.html#M000437
>
> You can pass parameters to #new and it will pass them to the block.
> You can use this technique to use a variable in the block that is
> different for each thread, like this:
>
> def testfunc(id)
>   total = id + 5
>   puts "id #{id} is #{total}"
> end
>
> threads = []
> numberlist = [1, 2, 3]
> for id in numberlist
>  threads << Thread.new(id) {|my_id| testfunc(my_id)}
> end
>
> threads.each { |aThread|  aThread.join }
>
> $ ruby threads.rb
> id 1 is 6
> id 2 is 7
> id 3 is 8
>
> Jesus.

Thanks both of you for your answer.

Regards