module Utilrb::EventLoop::Forwardable
The EventLoop::Forwardable
module provides delegation of specified methods to a designated object like the ruby ::Forwardable module but defers the method call to a thread pool of an event loop if a callback is given. After the call returned the callback is called from the event loop thread while it is processing its event at the end of each step.
To ensure thread safety for all kind of objects the event loop defers only one method call per object in parallel even if the method is called without any callback. For this mechanism a sync key is used which is by default the designated object but can be set to any custom ruby object. If a method call is thread safe the sync key can be set to nil allowing the event loop to call it in parallel while another none thread safe method call of the designated object is processed.
@note It is not possible to delegate methods where the target method needs
a code block.
@author Alexander Duda <Alexander.Duda@dfki.de>
Public Instance Methods
Defines a method as delegator instance method with an optional alias name ali.
Method calls to ali will be delegated to accessor.method. If an error occurres during proccessing it will be raised like in the case of the original object but also forwarded to the error handlers of event loop.
Method calls to ali(*args,&block) will be delegated to accessor.method(*args) but called from a thread pool. Thereby the code block is used as callback called from the main thread after the call returned. If an error occurred it will be:
* given to the callback as second argument * forwarded to the error handlers of the event loop * raised at the beginning of the next step if not marked as known error
To overwrite an error the callback can return :ignore_error or a new instance of an error. In an event of an error the error handlers of the event loop will not be called or called with the new error instance.
ali do |result,exception| if exception MyError.new else puts result end end ali do |result,exception| if exception :ignore_error else puts result end end
If the callback accepts only one argument the callback will not be called in an event of an error but the error will still be forwarded to the error handlers.
If the result shall be filtered before returned a filter method can be specified which is called from the event loop thread just before the result is returned.
@example
class Dummy # non thread safe method def test(wait) sleep wait Thread.current end # thread safe method def test_thread_safe(wait) sleep wait Thread.current end end class DummyAsync extend Utilrb::EventLoop::Forwardable def_event_loop_delegator :@obj,:@event_loop,:test,:alias => :atest def_event_loop_delegator :@obj,:@event_loop,:test_thread_safe,:sync_key => false def initialize(event_loop) @event_loop = event_loop @obj = Dummy.new end end event_loop = EventLoop.new test = DummyAsync.new(event_loop) puts test.atest 2 test.atest 2 do |result| puts result end test.thread_safe 2 do |result| puts result end sleep(0.1) event_loop.step
@param [Symbol] accessor The symbol for the designated object. @param [Symbol] event_loop The event loop accessor. @param [Symbol] method The method called on the designated object. @param [Hash] options The options @option options [Symbol] :alias The alias of the method @option options [Symbol] :sync_key The sync key @option options [Symbol] :filter The filter method @option options [Symbol] :on_error Method which is called if an error occured @option options [class] :known_errors Known errors which will be rescued but still be forwarded. @see sync
# File lib/utilrb/event_loop.rb, line 824 def def_event_loop_delegator(accessor,event_loop, method, options = Hash.new ) Forward.def_event_loop_delegator(self,accessor,event_loop,method,options) end
# File lib/utilrb/event_loop.rb, line 828 def def_event_loop_delegators(accessor,event_loop, *methods) Forward.def_event_loop_delegators(self,accessor,event_loop,*methods) end
# File lib/utilrb/event_loop.rb, line 832 def forward_to(accessor,event_loop,options = Hash.new,&block) obj = Forward.new(self,accessor,event_loop,options) obj.instance_eval(&block) end