On 17.06.2011 22:46, Mike Bethany wrote:
> Threadsafing a mixin module without using self.new or initialize.
>
> Project: Eventable - https://github.com/mikbe/eventable
>
> Background: https://github.com/mikbe/eventable/issues/4
>
> Problem Description:
> I need to threadsafe access to an instance variable, an array. To do so I've
> wrapped all methods that access the array in a mutex.synchronize block. The
> problem is I'm creating the mutex in each function using @eventable_mutex
> ||= Mutex.new which could cause collisions if two threads try to use a
> method that creates the mutex simultaneously.

You do not want to be creating the mutex from different threads - 
because then mutex creation itself is not thread safe.

> I've verified this could happen: https://gist.github.com/1031308
>
> Since this is a mixin module I can't use initialize to create the mutex
> instance variable

Why not?

module Anything
   def initialize(*a,&b)
     super
     @lock = Mutex.new
     @data = []
   end
end

class Other
   include Anything

   def initialize
     super # important!
     @another_var = 15
   end
end

> and I don't want to use trapself.new because if the class
> uses this method itself then the instance variable will never be created. My
> aversion to using self.new to create the instance variable is this: if I
> redefine a method to fix an issue it's not unreasonable for someone else to
> do the same thing. If their doing exactly what I did breaks what I did then
> it's a bad fix. (see https://github.com/mikbe/eventable/pull/3)
>
> So, my current idea for a solution is to create a class level mutex for the
> inheriting class that locks on the creation of the mutex, for instance:
> https://gist.github.com/1031419. This seems ugly though and I'm fairly new
> to Ruby so I'm wondering if I've missed, or simply don't know about,
> something that would be a better solution.

That approach does not scale well if you have lots of instances created 
concurrently.  If anything fails you can add a method which creates the 
mutex and which is called before the instance is used by multiple 
threads - as simple as that.  But I'd prefer the approach with #initialize.

Kind regards

	robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/