On Thu, Oct 27, 2011 at 3:59 AM, Charles Oliver Nutter
<headius / headius.com> wrote:
> On Wed, Oct 19, 2011 at 2:11 AM, Josh Cheek <josh.cheek / gmail.com> 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/