Feature #16792
Updated by Eregon (Benoit Daloze) over 4 years ago
Currently, Mutex in CRuby is held per Thread. In JRuby and TruffleRuby, Mutex is held per Fiber (because it's simply easier implementation-wise). While a user could theoretically notice the difference, it seems extremely uncommon in practice (probably incorrect synchronization). The usage pattern for a Mutex is using #synchronize or lock+unlock. Such a pattern protects/surrounds a region of code using some resource, and such a region of code is always on the same Fiber since it's on a given Ruby "stack". With #16786 it becomes more relevant to have Mutex held per Fiber, otherwise Mutex#lock will basically would hurt scalability of that proposal significantly. This means, if a Fiber does Mutex#lock and it's already held by another Fiber of the same Thread, and the Thread#scheduler is enabled, instead of just raising an error (which made sense before, because it would be a deadlock, but no longer the case with scheduler), error, or preventing switching entirely until #unlock (current state in #16786, makes Mutex#lock special and hurts scalability), #unlock, we would just go to the scheduler and schedule another Fiber (for instance, the one holding that Mutex, or any other ready to be run Fiber). This is not a new idea and in fact Crystal already does this with its non-blocking Fibers, which is very similar with #16786: https://github.com/crystal-lang/crystal/blob/612825a53c831ce7d17368c8211342b199ca02ff/src/mutex.cr#L72 Mutex#lock is just like other blocking operations, so let's make it so building on #16786. I believe it's the natural and intuitive thing to do for Fiber concurrency with a scheduler. Queue#pop and SizedQueue#push could be other candidates to handle in a similar way. Here is an early commit to make Mutex held per Fiber, it's quite trivial as you can see: https://github.com/ruby/ruby/compare/master...eregon:mutex-per-fiber It passes test-all and test-spec.