From: Nasir Khan Date: 2007-06-11T10:19:36+09:00 Subject: Re: Synchronized attr_accessor ------=_Part_102974_18206413.1181524777355 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline Thanks for the feedback. Here is a refinement - #--------------------- module MethodSynchronizer def MethodSynchronizer.included(into) into.sync_methods.each do |m| MethodSynchronizer.wrap_method(into, m) end end def MethodSynchronizer.wrap_method(klass, meth) klass.class_eval do alias_method "__nonsync_#{meth}", "#{meth}" require 'thread' @@__ms_c_lock = Mutex.new define_method(meth) do |*args| @@__ms_c_lock.synchronize { @__ms_lock = Mutex.new unless @__ms_lock } unless @__ms_lock @__ms_lock.synchronize do self.send("__nonsync_#{meth}",*args) end end end end end #---------------------- The @@__ms_c_lock is a class level lock which will be taken only of mutex @__ms_lock is not yet created. This is the double checked lock pattern where the mutex is again checked after taking the class level lock. Thanks Nasir On 6/10/07, Caleb Clausen wrote: > > Nasir Khan wrote: > > define_method(meth) do |*args| > > @__ms_lock = Mutex.new unless @__ms_lock > > @__ms_lock.synchronize do > > self.send("__nonsync_#{meth}",*args) > > end > > end > > This still isn't completely thread-safe, I'm afraid. If the lock > doesn't exist yet and two threads both call some synchronized method > on the same object, you've got a race condition. I'd suggest creating > the lock upfront, before the synchronization wrappers are defined.... > unfortunately, that makes implementing this idea a bit more > complicated. > > ------=_Part_102974_18206413.1181524777355--