From: Robert Klemme Date: 2011-10-27T23:00:48+09:00 Subject: Re: Ruby and threading On Thu, Oct 27, 2011 at 3:59 AM, Charles Oliver Nutter wrote: > On Wed, Oct 19, 2011 at 2:11 AM, Josh Cheek wrote: >> * Other times I ran it under JRuby, it detected the corrupt data with >> 'ConcurrencyError: Detected invalid array contents due to unsynchronized >> modifications with concurrent users' > > We do our best to detect this for Array, and at some point we'll try > to do it for Hash (Hash will currently raise errors from Java like > ArrayIndexOutOfBoundsException...still rescuable, but not as nice). It > would be cool if Ruby incorporated some explicitly thread-safe > collections by default, but there are gems that provide such things > right now. > > FWIW, it's almost impossible to have threadsafe data structures that > perform as well as non-threadsafe data structures, which is why we've > always opted to keep Array and Hash the way they are. Hopefully people > are starting to learn that the alternatives aren't that bad, like > using external threadsafe libs or simply mutexing around all accesses. Actually it is not possible to provide thread safe collections out of the box which handle all use cases. I have frequently seen people use Collections.synchronizedMap() in Java and not realize that their code is not thread safe. There are two typical scenarios in Java where you need to manually define the scope of the mutex by externally synchronizing: 1. When you invoke more than one method on the object which need to act on the same state. 2. Iterating a collection (Collections.synchronizedMap() does not prevent ConcurrentModificationException). (Note: 2 does not apply in Ruby when iterating with #each and relatives but 1 also is valid in Ruby land) People need to understand that thread safety is not a property of a class (or type) which you can easily gain by just synchronizing all methods (it works in some cases though) but of the code which accesses shared state. So from an educational point of view the effect of providing objects with all methods synchronized may not be ideal because it may convey a false sense of safety. Having said that it would probably be a good idea to add something like this to the standard library which can be used for any object require 'monitor' class SynchronizingWrapper < BasicObject def initialize(o) @lock = ::Monitor.new @obj = o end def synchronize(&b) @lock.synchronize(&b) end def method_missing(*a, &b) @lock.synchronize do @obj.send(*a, &b) end end end Wrapping a collection with this gets you pretty far because for example Hash already has methods #fetch and the default proc so the usual idiom of if h.contains_key?(x); y=h[x];else;h[x]=y=create;end is not needed often. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/