From: Charles Oliver Nutter Date: 2008-12-03T13:45:31+09:00 Subject: [ruby-core:20238] Re: autoload and concurrency Yehuda Katz wrote: > Merb uses autoload rather extensively. We have lately observed some > disturbing behavior around concurrency. > > Effectively, because autoload removes the flag before loading the file, > if two threads concurrently attempt to access an autoloaded constant, > one of the threads can get a NameError. > > It's easy to reproduce this by adding a sleep to the file being loaded > before the constant is defined, and then spinning up two threads that > both try to use the constant. This is reproducible in MRI; it does not > only happen with JRuby's true parallel execution. > > The worst part is that no user action can solve this problem: because > autoloading is magic, it's impossible for the user to lock the resulting > require. In effect, this makes autoloading completely useless for > threaded environments. Is this intentional? > > Is there something we can do at the language level to ameliorate this > problem? I've spent some time looking into this on Yehuda's behalf, and I believe there's no way to make this work without a behavioral change to autoload. Autoload is part of the normal constant lookup scheme. When defining an autoload, a special value is inserted into the target constant table with autoload file information. As constants are looked up, if one of these special values is encountered an autoload is triggered. Currently, the basic logic of autoload is like this: 1. The special value is removed from the constant table 2. The associated file is required, and presumably defines the constant 3. The constant is re-looked-up after the require completes The problem lies in step 1 here. There can be a gap between the time the special value is removed from the constant table and the time the required file redefines it. During this period, another thread may try to request the constant value. Since the autoload value has been removed and the new value has not yet replaced it, the constant search continues (and eventually fails with a NameError). The primary behavioral change needed would be to not remove the autoload value, or to replace it with a new marker indicating "autoload in progress". This would require changes to anything that looks up constants, so it would know not to initiate a new autoload require nor continue up the constant scope chain but to *block* until the autoload is complete. I believe this is the only way to make autoload threadsafe. I will also agree with Yehuda that a thread-unsafe autoload is broken, since it means the primary use case of autoload (delayed loading a file and definition of a constant) can't be used in the presence of threads. - Charlie