Will add the lock and the TODO.

Btw, the bug I was running into was that "threadObject.inspect" was incorrectly 
binding to KernelOps.Inspect rather than ThreadOps.Inspect when executed on a 
second thread. The first thread was in the middle of calling EnsureInitialized 
on the Thread class.

Thanks,
Shri

From: Tomas Matousek
Sent: Tuesday, December 16, 2008 7:59 AM
To: Shri Borde
Subject: RE: Lock during module initialization

This seems to be a good temporary workaround and it might be close to the right 
long term solution (could you add a TODO comment next to the lock statement?). 
There are no cycles in inheritance hierarchy (a module inclusion cannot be 
cyclic) and any time an uninitialized module is accessed we need to initialize 
only its ancestors.  (Actually, the _mixins array should contain all mixins 
serialized into a list - i.e. all mixins included into the mixins in the array 
are contained in the array as well. That implies we might not need to call the 
virtual EnsureInitialized method on the _mixins's elements. There are more such 
improvements to be made in module initialization and they should lead to better 
performance and thread-safety as well.

There has been a discussion on Ruby list recently on how 'require' should work 
in a multi-threaded program. The conclusion seems to be similar to the Python's 
approach (a global mutex for require). 'require' is thread-unsafe in today's 
MRI. In general, MRI's behavior is mostly undefined in multi-threaded 
environment today.

(BTW: The built-ins initialization we are doing is a little bit more 
complicated than in MRI since we are postponing it until it is really needed. 
In MRI all built-ins are initialized during startup. We initialize them as they 
are accessed.)

Tomas

From: Shri Borde
Sent: Monday, December 15, 2008 11:20 PM
To: Tomas Matousek
Subject: Lock during module initialization

IronRuby code was misbehaving and calling an incorrect method in the presence 
of multiple threads. This was because RubyModule.EnsureInitialized just returns 
if _state is, for example, State.Initializing. I add the lock shown below which 
fixes the problem.

        internal virtual void EnsureInitialized() {
            lock(this) {
                if (_state == State.Uninitialized) {
                    for (int i = 0; i < _mixins.Length; i++) {
                        _mixins[i].EnsureInitialized();
                    }

                    if (_state == State.Uninitialized) {
                        InitializeMembers();
                    }
                }
            }
        }

This probably opens up the possibility of deadlocks if there are 
mutually-dependent modules or some such complicated scheme. Is the lock good 
enough for now since it fixes wrong behavior which is hard to track down? A 
deadlock will be easier to debug.

What is the long term story here? Python allows module importing on only one 
thread at a time. The CLR maintains a list of types being initialized and knows 
to break cycles of mutually dependent cctors. What does MRI do? I don't think 
green threads make the problem any simpler. What does JRuby do?

Thanks,
Shri

_______________________________________________
Ironruby-core mailing list
Ironruby-core@rubyforge.org
http://rubyforge.org/mailman/listinfo/ironruby-core

Reply via email to