From: Robert Klemme Date: 2011-06-18T06:45:45+09:00 Subject: Re: Threadsafing a mixin module without using self.new or initialize. 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/