Project

General

Profile

Feature #8556

Updated by ko1 (Koichi Sasada) over 3 years 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 
         mutex.lock 
         target.__send__(m, *args, &block) 
       ensure 
         mutex.unlock 
       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