Bug #4480

Thread-local variables issue: Thread#[] returns nil when called first time

Added by Andrei Kulakov about 3 years ago. Updated almost 3 years ago.

[ruby-core:<unknown>]
Status:Closed
Priority:Normal
Assignee:Hiroshi Nakamura
Category:doc
Target version:1.9.3
ruby -v:- Backport:

Description

=begin
In ruby 1.9.2p180
t = Thread.new do
Thread.current[:var] = "var"
Thread.stop
end

p t[:var] #=> nil
p t[:var] #=> "var"

In ruby 1.8.7
p t[:var] #=> "var"
p t[:var] #=> "var"
=end

thread_rdoc_fix.patch Magnifier (1.14 KB) Andrei Kulakov, 03/12/2011 08:26 PM

Associated revisions

Revision 32260
Added by Hiroshi Nakamura almost 3 years ago

  • thread.c (rbthreadlocal_aref): RDoc fix. Thread#[] example had a race. See #4480.

History

#1 Updated by Robert Gleeson about 3 years ago

=begin
Hi Andrei,

I don't think this is a bug. You should call Thread#join before you call Kernel.p.
Your thread may or may not not have been run by the time you call Kernel.p, and you may get
inconsistent results such as t[:var] being nil sometimes, and being "var" at other times.

Thanks,
Rob
=end

#2 Updated by Andrei Kulakov about 3 years ago

=begin
Hi Robert,

Thanks a lot. You are totally right about Thread#join.

But what the solution in my particular case, how do I get thread-local variable when Thread.stop called within a thread.
t = Thread.new do
Thread.current[:var] = "var"
Thread.stop
end

t.join

p t[:var]
p t[:var]

yiedls
threads.rb:6:in join': deadlock detected (fatal)
from threads.rb:6:in
'
and it's supposed to be like that.

Apologies if it's a stupid question.

=end

#3 Updated by Andrei Kulakov about 3 years ago

=begin
I also wanted to say this is rdoc's example of Thread#[] the one that tricked me.

Right now this is:
a = Thread.new { Thread.current["name"] = "A"; Thread.stop }
b = Thread.new { Thread.current[:name] = "B"; Thread.stop }
c = Thread.new { Thread.current["name"] = "C"; Thread.stop }
Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
produces:
#: C
#: B
#: A
#:

But on some slower machine it will produce different results.

Maybe it's better to change this example to something like following:

a = Thread.new { Thread.current["name"] = "A" }
b = Thread.new { Thread.current[:name] = "B" }
c = Thread.new { Thread.current["name"] = "C" }

Thread.list.each do |thr|
thr.join unless thr == Thread.main
puts "#{thr.inspect}: #{thr[:name]}"
end
produces:
#:
#: A
#: B
#: C

Or some other more consistent example than current.
=end

#4 Updated by Yui NARUSE almost 3 years ago

  • Status changed from Open to Assigned
  • Assignee set to Hiroshi Nakamura

#5 Updated by Koichi Sasada almost 3 years ago

  • ruby -v changed from ruby 1.9.2p180 (2011-02-18 revision 30909) [i686-linux] to -

(2011/06/26 18:24), Yui NARUSE wrote:

In ruby 1.9.2p180
t = Thread.new do
Thread.current[:var] = "var"
Thread.stop
end

p t[:var] #=> nil
p t[:var] #=> "var"

In ruby 1.8.7
p t[:var] #=> "var"
p t[:var] #=> "var"

It seems intentional. When the first access, the Thread.current[:var]
is not initialized (not reached the initialization code).

--
// SASADA Koichi at atdot dot net

#6 Updated by Hiroshi Nakamura almost 3 years ago

On Sun, Jun 26, 2011 at 20:12, SASADA Koichi ko1@atdot.net wrote:

It seems intentional.  When the first access, the Thread.current[:var]
is not initialized (not reached the initialization code).

You're right. I took this ticcket since it would be a RDoc issue.

#7 Updated by Hiroshi Nakamura almost 3 years ago

  • Category set to doc
  • Target version changed from 1.9.2 to 1.9.3

Updated RDoc at r32260 based on Andrei's patch. I just wanted to remove Thread.main thing to concentrate Thread#[] behavior. Thanks!

#8 Updated by Hiroshi Nakamura almost 3 years ago

  • Status changed from Assigned to Closed

Also available in: Atom PDF