So I have been looking at some code I inherited. I see two examples of
thread use in this. Wondering what the difference is. I’ve made up two
examples that show this, wondering what the difference is, and why to
use one or the other.
Thread.start(obj1, obj2, myString) do |thing1, thing2, thing3| #use the variables named thing1, thing2, thing3.
end
And then this way…
—Example 2-----------------------------------------------------------
obj1 = SomeObject.new()
obj2 = SomeOtherObject.new()
obj3 = “helloworld”
Thread.start() do #use the objects named obj1, obj2, obj3
end
So, What is the reason for doing Example 1 versus Example 2. The 2nd
example seems simpler in my book. My guess is it has something to do
with how the objects may be used outside the thread?
So, What is the reason for doing Example 1 versus Example 2. The 2nd
example seems simpler in my book. My guess is it has something to do
with how the objects may be used outside the thread?
See 7stud’s examples. It’s not about objects but about scope of
variables.
So does that mean these are functionally identical?
Thread.new(a) { |b| do_something_with b }
… and …
Thread.new { b=a; do_something_with b }
Or is there a potential race condition caused by possibly deferred
execution of the block, which is avoided by performing the “renaming”
assignment in the parent thread? I’m trying to think of an example, but
am
having trouble.
Or is there a potential race condition caused by possibly deferred
execution of the block, which is avoided by performing the “renaming”
assignment in the parent thread? I’m trying to think of an example, but am
having trouble.
Thought of one (sorry for replying to myself):
a = 1
loop do
Thread.new { b=a; p b }
a += 1
end
… where a += 1 is likely to run before b=a; as opposed to …
a = 1
loop do
Thread.new(a) { |b| p b }
a += 1
end
… where passing the value of a to Thread#new is guaranteed to happen
before a += 1, so b will always have the right value.
On Sun, 30 Dec 2012 13:43:53 +0100, Matthew K. [email protected] wrote:
assignment in the parent thread? I’m trying to think of an example, but am
having trouble.
There’s another thing apart from the race conditions. These are mostly
equivalent (except for what you’ve already said) only if there is no
variable called b in the outer scope - if there was one, in your
second example b=a will assign to it and change the value outside the
thread. In the first case, the “outer” b will simple be inaccessible
inside the thread, but its value outside the thread won’t be changed.
(The above only applies to Ruby 1.9 and newer, the semantics for both
versions on 1.8 are the same - if there is an “outer” b, its value will
change. This is obviously not always what the coder has intended and so
it was changed in 1.9.)
Experience in multithreaded environments. Without an explicit mutex or
other locking mechanism (or call to Thread#join) there’s no guarantee
that
either will run before the other. I know that in MRI the GVL is a large
player, but I’m not being implementation-specific here.
If I really had to guess, in a truly parallel multithreaded environment,
assuming that the block begins execution at the same instant as the line
after Thread.new, I’d guess that the b=a operation would happen before
the a = ..., assuming that a += 1 is actually broken down into a = a + 1 which has an extra operation and so should take longer. However in a
less parallel system I would have assumed the current thread would
execute
a bit before the child thread was given some CPU time, so a += 1 would
have a chance to complete before b=a. In either case it’s something
over
which I as the programmer do not have any control.
There’s another thing apart from the race conditions. These are mostly
equivalent (except for what you’ve already said) only if there is no
variable called b in the outer scope - if there was one, in your
second
example b=a will assign to it and change the value outside the thread.
In
the first case, the “outer” b will simple be inaccessible inside the
thread, but its value outside the thread won’t be changed.
Ah, that’s a really good point. I’d forgotten that 1.9 masks variables
with
the same name as block parameters. Now that you’ve said it, I remember
having to refactor a bunch of OptParse code that used to use: