Feature #8556

Updated by Nobuyoshi Nakada over 1 year ago

=begin
I propose adding (({MutexedDelegator})) MutexedDelegator as a simple way to wrap any object with a thread-safe wrapper, via existing delegation logic in ((%delegate.rb%)). delegate.rb.

(({Delegator})) Delegator provides a way to pass method calls through to a wrapped object. (({SimpleDelegator})) SimpleDelegator is a trivial implementation that just holds the object in an instance variable. (({MutexedDelegator})) MutexedDelegator would extend (({SimpleDelegator})) SimpleDelegator and only override initialize and (({method_missing})) method_missing as follows:



class MutexedDelegator < SimpleDelegator

def initialize(*)

super

@mutex = Mutex.new

end



def method_missing(m, *args, &block)

target, mutex = self.__getobj__, @mutex
begin

begin
mutex.lock

target.__send__(m, *args, &block)
ensure

ensure
mutex.unlock
end

end
end
end


The only changes here are:

* (({Mutex#lock})) Mutex#lock and (({unlock})) unlock logic wrapping the send
* No (({respond_to?})) respond_to? check; I'm not sure why it's there to begin with, since if we're in (({method_missing})) method_missing the (({super()})) super() call will fail just like a normal (({method_missing})) method_missing failure anyway
* No backtrace manipulation. This does not work on JRuby and Rubinius anyway, and in this case I feel that the delegator should not hide itself, since there's real behavior change happening.

This is a trivial addition to stdlib that would make it simple to synchronize all calls to a given object in the same way as the JDK's (({Collections.synchronizedSet}))/(({Map}))/(({List})) Collections.synchronizedSet/Map/List calls.
=end

Back