Bug #8444
openRegexp vars $~ and friends are not thread local
Description
In the docs for the Regexp special variables, $~
and friends, it says "These global variables are thread-local and method-local variables". However the following gives an unexpected result:
def get_proc
proc do |str|
str =~ /(.+)/
sleep 0.1
puts "got #{$1} from #{str}\n"
end
end
proc = get_proc
t1 = Thread.new { proc.call "abc" }
t2 = Thread.new { proc.call "def" }
t1.join
t2.join
This outputs the following:
got abc from abc
got abc from def
The expected result is of course:
got abc from abc
got def from def
Clearly the variables are being scoped to the get_proc
method and are being shared by both threads. This runs contrary to the documentation and also to expectations.
This behaviour should either be changed, or the documentation updated to reflect the actual behaviour.
Interestingly, the following does work as expected:
proc = proc do |str|
str =~ /(.+)/
sleep 0.1
puts "got #{$1} from #{str}\n"
end
t1 = Thread.new { proc.call "abc" }
t2 = Thread.new { proc.call "def" }
t1.join
t2.join
Updated by jeremyevans0 (Jeremy Evans) over 5 years ago
- Backport deleted (
1.9.3: UNKNOWN, 2.0.0: UNKNOWN)
This behavior is still present in the master branch and it does seem like a bug to me. It does seems specific to returning a closure from a method and having two separate threads call that closure.
It doesn't occur if you pass the proc directly to Thread.new
:
def get_proc
lambda do |str|
str =~ /(.+)/
sleep 0.1
puts "got #{$1} from #{str}\n"
end
end
proc = get_proc
t1 = Thread.new("abc", &proc)
t2 = Thread.new("def", &proc)
t1.join
t2.join
or if you switch to calling a method directly:
def get_proc str
str =~ /(.+)/
sleep 0.1
puts "got #{$1} from #{str}\n"
end
t1 = Thread.new { get_proc "abc" }
t2 = Thread.new { get_proc "def" }
t1.join
t2.join
From some debugging, one difference between the two cases in the original post is that different branches are taken in lep_svar
, with the failing case taking the if
and the passing case taking the else
.
Updated by jeremyevans0 (Jeremy Evans) over 5 years ago
- Related to Bug #12689: Thread isolation of $~ and $_ added
Updated by ko1 (Koichi Sasada) over 5 years ago
- Assignee set to ko1 (Koichi Sasada)
Updated by jeremyevans0 (Jeremy Evans) about 5 years ago
- Has duplicate Bug #14364: Regexp last match variable in procs added
Updated by jeremyevans0 (Jeremy Evans) almost 5 years ago
- Related to Bug #16448: regex global variables are working differently depending on scope added
Updated by Anonymous about 1 year ago
RubyConf Hack Day: suggest to close
Updated by jemmai (Jemma Issroff) about 1 year ago
- Status changed from Open to Closed
Updated by jemmai (Jemma Issroff) about 1 year ago
- Status changed from Closed to Open
Updated by nobu (Nobuyoshi Nakada) about 1 year ago
- Description updated (diff)
"Thread-local" in that sentence was wrong, and removed at 932dd9f10e684fa99b059054fbc934607d85b45a, but "method-local" is removed too.
Updated by Dan0042 (Daniel DeLorme) about 1 year ago
nobu (Nobuyoshi Nakada) wrote in #note-9:
"Thread-local" in that sentence was wrong, and removed at 932dd9f10e684fa99b059054fbc934607d85b45a, but "method-local" is removed too.
Indeed, the documentation used to say "Regexp Global Variables" or "Special Global Variables" and this has been reduced to just "Global Variables" which I think is quite misleading. Sure they have the $
sigil, but they're not global at all. If anything, "Special Variables" would be more accurate.
Updated by hsbt (Hiroshi SHIBATA) 8 months ago
- Status changed from Open to Assigned
Updated by jeremyevans0 (Jeremy Evans) 3 days ago
- Related to Bug #20807: String#gsub fails when called from string subclass with a block passed added