On Wed, Oct 19, 2011 at 8:32 AM, Josh C. removed_email_address@domain.invalid
wrote:
When it’s in a lib you don’t control, it’s useful. A wrapped C lib is
probably the best example, but even if its in someone else’s gem, it’s
relevant. Debugging libs takes a lot of time and effort, especially for
something nondeterministic that may or may not reproduce itself.
Rbx / JRuby / MacRuby will need resources to educate their users about how
to write safe code, and may also need to maintain a list of safe gems.
The GIL doesn’t eliminate the importance of writing thread safe code, it
just masks the symptoms of unsafe code in certain cases.
It’s not some magical panacea. Users of Ruby 1.9 who use threads need to
be
just as vigilant about the thread safety of their code. Otherwise their
programs are working by accident, such as your “needs_gil.rb”. The fact
that
program works is an implementation detail of the GIL on 1.9.2, it’s not
as
if Matz has said “all operations on arrays should be automatically
thread
synchronized”, which is still possible on VMs without a GIL (although
I’m
surprised the above doesn’t trigger a ConcurrentModificationException on
JRuby)
As an example of thread safety problems even with a GIL, try running the
following on 1.9.2:
– snip –
require ‘thread’
numbers = [0]
threads = []
#lock = Mutex.new
100.times do
threads << Thread.new do
size = nil
begin
#lock.synchronize do
value = rand(101)
if value == numbers.last + 1
sleep 0.01
numbers << value
end
size = numbers.size
#end
end while size < 100
end
end
threads.each(&:join)
p numbers
– snip –
It’s a bit contrived and goofy, but whatever. The output should look
like
this:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96,
97, 98, 99,100]
However if you run the above code with the lock commented out, even on
1.9.2
you’ll get something like this instead:
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
Broken, thread-unsafe code is broken, thread-unsafe code. It doesn’t
matter
if it magically happens to work by accident in 1.9.2. It’s still broken.
The
GIL doesn’t mean you can avoid teaching users of threads about thread
safety, or that you don’t need to maintain a list of safe gems (
railsplugins.org is trying to do this, BTW, although I wish it were
built
into RubyGems). You still need to do these things on 1.9.2. The
difference
is the GIL will mask certain thread safety bugs, but not all of them.
“I don’t need to worry about thread safety because the GIL will take
care of
it for me” is definitely the wrong attitude.