Class: Eventbox
- Inherits:
-
Object
- Object
- Eventbox
- Extended by:
- Boxable
- Defined in:
- lib/eventbox.rb,
lib/eventbox/timer.rb,
lib/eventbox/boxable.rb,
lib/eventbox/version.rb,
lib/eventbox/sanitizer.rb,
lib/eventbox/event_loop.rb,
lib/eventbox/thread_pool.rb,
lib/eventbox/object_registry.rb,
lib/eventbox/argument_wrapper.rb
Direct Known Subclasses
Defined Under Namespace
Modules: ArgumentWrapper, Boxable, Sanitizer, Timer Classes: AbortAction, Action, AsyncProc, CompletionProc, ExternalProc, InternalProc, InvalidAccess, MultipleResults, ObjectRegistry, SyncProc, Thread, ThreadPool, WrappedException, WrappedObject, WrappedProc, YieldProc
Constant Summary collapse
- VERSION =
"0.1.0"
Class Method Summary collapse
-
.action(name, &block) ⇒ Object
extended
from Boxable
private
Define a private method for asynchronous execution.
-
.async_call(name, &block) ⇒ Object
extended
from Boxable
private
Define a threadsafe method for asynchronous (fire-and-forget) calls.
-
.attr_accessor(name) ⇒ Object
extended
from Boxable
private
Threadsafe read and write access to instance variables.
-
.attr_reader(name) ⇒ Object
extended
from Boxable
private
Threadsafe read access to instance variables.
-
.attr_writer(name) ⇒ Object
extended
from Boxable
private
Threadsafe write access to instance variables.
-
.eventbox_options ⇒ Hash
Retrieves the Eventbox options of this class.
-
.sync_call(name, &block) ⇒ Object
extended
from Boxable
private
Define a method for synchronous calls.
-
.with_options(**options) ⇒ Object
Create a new derived class with the given options.
-
.yield_call(name, &block) ⇒ Object
extended
from Boxable
private
Define a method for calls with deferred result.
Instance Method Summary collapse
-
#async_proc(name = nil, &block) ⇒ Object
private
Create a proc object for asynchronous (fire-and-forget) calls similar to Boxable#async_call.
-
#init(*args) ⇒ Object
private
Initialize a new Eventbox instance.
-
#shared_object(object) ⇒ Object
Mark an object as to be shared instead of copied.
-
#shutdown!(&completion_block) ⇒ Object
Force stop of all action threads spawned by this Eventbox instance.
-
#sync_proc(name = nil, &block) ⇒ Object
private
Create a Proc object for synchronous calls similar to Boxable#sync_call.
-
#yield_proc(name = nil, &block) ⇒ Object
private
Create a Proc object for calls with deferred result similar to Boxable#yield_call.
Class Method Details
.action(name, &block) ⇒ Object (private) Originally defined in module Boxable
Define a private method for asynchronous execution.
The call to the action method returns immediately after starting a new action. It returns an Action object. By default each call to an action method spawns a new thread which executes the code of the action definition. Alternatively a threadpool can be assigned by Eventbox.with_options.
All method arguments are passed through the Sanitizer.
Actions can return state changes or objects to the event loop by calls to methods created by #async_call, #sync_call or #yield_call or through calling Eventbox#async_proc, Eventbox#sync_proc or Eventbox#yield_proc objects. To avoid unsafe shared objects, an action has it’s own set of local variables or instance variables. It doesn’t have access to variables defined by other methods.
The Action object can be used to interrupt the program execution by an exception. See Action for further information. If the action method accepts one more argument than given to the action call, it is set to corresponding Action instance:
async_call def init
do_something("value1")
end
action def do_something(str, action)
str # => "value1"
action.current? # => true
# `action' can be passed to event scope or external scope,
# in order to send a signals per Action#raise
end
.async_call(name, &block) ⇒ Object (private) Originally defined in module Boxable
Define a threadsafe method for asynchronous (fire-and-forget) calls.
The created method can be safely called from any thread. All method arguments are passed through the Sanitizer. Arguments prefixed by a € sign are automatically passed as WrappedObject.
The method itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use #action in these cases.
In contrast to #sync_call it’s not possible to call external blocks or proc objects from #async_call methods.
The method always returns self
to the caller.
.attr_accessor(name) ⇒ Object (private) Originally defined in module Boxable
Threadsafe read and write access to instance variables.
Attention: Be careful with read-modify-write operations - they are not atomic but are executed as two independent operations.
This will lose counter increments, since ‘counter` is incremented in a non-atomic manner:
attr_accessor :counter
async_call def start
10.times { do_something }
end
action def do_something
self.counter += 1
end
Instead don’t use accessors but do increments within one method call like so:
async_call def start
10.times { do_something }
end
action def do_something
increment 1
end
async_call def increment(by)
@counter += by
end
.attr_reader(name) ⇒ Object (private) Originally defined in module Boxable
Threadsafe read access to instance variables.
.attr_writer(name) ⇒ Object (private) Originally defined in module Boxable
Threadsafe write access to instance variables.
.eventbox_options ⇒ Hash
Retrieves the Eventbox options of this class.
46 47 48 49 50 51 52 |
# File 'lib/eventbox.rb', line 46 def self. { threadpool: Thread, guard_time: 0.5, gc_actions: false, } end |
.sync_call(name, &block) ⇒ Object (private) Originally defined in module Boxable
Define a method for synchronous calls.
The created method can be safely called from any thread. It is simular to #async_call, but the method waits until the method body is executed and returns its return value. Since all processing within the event scope of an Eventbox instance must not involve blocking operations, sync calls can only return immediate values. For deferred results use #yield_call instead.
It’s possible to call external blocks or proc objects from #sync_call methods. Blocks are executed by the same thread that calls the #sync_call method to that time.
All method arguments as well as the result value are passed through the Sanitizer. Arguments prefixed by a € sign are automatically passed as WrappedObject.
The method itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use #action in these cases.
.with_options(**options) ⇒ Object
Create a new derived class with the given options.
The options are merged with the options of the base class. The following options are available:
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/eventbox.rb', line 70 def self.(**) Class.new(self) do define_singleton_method(:eventbox_options) do super().merge() end def self.inspect klazz = self until name=klazz.name klazz = klazz.superclass end "#{name}#{}" end end end |
.yield_call(name, &block) ⇒ Object (private) Originally defined in module Boxable
Define a method for calls with deferred result.
This call type is simular to #sync_call, however it’s not the result of the method that is returned. Instead the method is called with one additional argument in the event scope, which is used to yield a result value or raise an exception. In contrast to a return
statement, the execution of the method continues after yielding a result.
The result value can be yielded within the called method, but it can also be stored and called by any other event scope or external method, leading to a deferred method return. The external thread calling this method is suspended until a result is yielded. However the Eventbox object keeps responsive to calls from other threads.
The created method can be safely called from any thread. If yield methods are called in the event scope, they must get a Proc object as the last argument. It is called when a result was yielded.
It’s possible to call external blocks or proc objects from #yield_call methods up to the point when the result was yielded. Blocks are executed by the same thread that calls the #yield_call method to that time.
All method arguments as well as the result value are passed through the Sanitizer. Arguments prefixed by a € sign are automatically passed as WrappedObject.
The method itself as well as the Proc object might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use #action in these cases.
Instance Method Details
#async_proc(name = nil, &block) ⇒ Object (private)
Create a proc object for asynchronous (fire-and-forget) calls similar to Eventbox::Boxable#async_call.
It can be passed to external scope and called from there like so:
class MyBox < Eventbox
sync_call def print(p1)
async_proc do |p2|
puts "#{p1} #{p2}"
end
end
end
MyBox.new.print("Hello").call("world") # Prints "Hello world"
The created object can be safely called from any thread. All block arguments are passed through the Sanitizer. The block itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use Eventbox::Boxable#action in these cases.
The block always returns self
to the caller.
181 182 183 |
# File 'lib/eventbox.rb', line 181 def async_proc(name=nil, &block) @__event_loop__.new_async_proc(name=nil, &block) end |
#init(*args) ⇒ Object (private)
Initialize a new Eventbox instance.
This method is executed for initialization of a Eventbox instance. This method receives all arguments given to Eventbox.new
after they have passed the Sanitizer. It can be used like initialize
in ordinary ruby classes including super
to initialize included modules or base classes.
#init can be defined as either Eventbox::Boxable#sync_call or Eventbox::Boxable#async_call with no difference. #init can also be defined as Eventbox::Boxable#yield_call, so that the new
call is blocked until the result is yielded. #init can even be defined as Eventbox::Boxable#action, so that each instance of the class immediately starts a new thread.
159 160 |
# File 'lib/eventbox.rb', line 159 def init(*args) end |
#shared_object(object) ⇒ Object
Mark an object as to be shared instead of copied.
A marked object is never passed as copy, but passed as reference. The object is therefore wrapped as WrappedObject when used in an unsafe scope. Wrapping as WrappedObject denies access from external/action scope to event scope objects and vice versa. It also denies access to objects originated from a foreign event scope. However the object can be passed as reference and is automatically unwrapped when passed back to the original scope. It can therefore be used to modify the original object even after traversing the boundaries.
Wrapping and unwrapping works even if the shared object is stored within another object as instance variable or within a collection class.
The mark is stored for the lifetime of the object, so that it’s enough to mark only once at object creation.
252 253 254 |
# File 'lib/eventbox.rb', line 252 public def shared_object(object) @__event_loop__.shared_object(object) end |
#shutdown!(&completion_block) ⇒ Object
Force stop of all action threads spawned by this Eventbox instance.
It is possible to enable automatic cleanup of action threads by the garbage collector through with_options. However in some cases automatic garbage collection doesn’t remove all instances due to running action threads. Calling shutdown! when the work of the instance is done, ensures that it is GC’ed in all cases.
If #shutdown! is called externally, it blocks until all actions threads have terminated.
If #shutdown! is called in the event scope, it just triggers the termination of all action threads and returns afterwards. Optionally #shutdown! can be called with a block. It is called when all actions threads terminated.
267 268 269 |
# File 'lib/eventbox.rb', line 267 public def shutdown!(&completion_block) @__event_loop__.shutdown(&completion_block) end |
#sync_proc(name = nil, &block) ⇒ Object (private)
Create a Proc object for synchronous calls similar to Eventbox::Boxable#sync_call.
It can be passed to external scope and called from there like so:
class MyBox < Eventbox
sync_call def print(p1)
sync_proc do |p2|
"#{p1} #{p2}"
end
end
end
puts MyBox.new.print("Hello").call("world") # Prints "Hello world"
The created object can be safely called from any thread. All block arguments as well as the result value are passed through the Sanitizer. The block itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use Eventbox::Boxable#action in these cases.
This Proc is simular to #async_proc, but when the block is invoked, it is executed and it’s return value is returned to the caller. Since all processing within the event scope of an Eventbox instance must not execute blocking operations, sync procs can only return immediate values. For deferred results use #yield_proc instead.
206 207 208 |
# File 'lib/eventbox.rb', line 206 def sync_proc(name=nil, &block) @__event_loop__.new_sync_proc(name=nil, &block) end |
#yield_proc(name = nil, &block) ⇒ Object (private)
Create a Proc object for calls with deferred result similar to Eventbox::Boxable#yield_call.
It can be passed to external scope and called from there like so:
class MyBox < Eventbox
sync_call def print(p1)
yield_proc do |p2, result|
result.yield "#{p1} #{p2}"
end
end
end
puts MyBox.new.print("Hello").call("world") # Prints "Hello world"
This proc type is simular to #sync_proc, however it’s not the result of the block that is returned. Instead the block is called with one additional argument in the event scope, which is used to yield a result value. The result value can be yielded within the called block, but it can also be called by any other event scope or external method, leading to a deferred proc return. The external thread calling this proc is suspended until a result is yielded. However the Eventbox object keeps responsive to calls from other threads.
The created object can be safely called from any thread. If yield procs are called in the event scope, they must get a Proc object as the last argument. It is called when a result was yielded.
All block arguments as well as the result value are passed through the Sanitizer. The block itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use Eventbox::Boxable#action in these cases.
236 237 238 |
# File 'lib/eventbox.rb', line 236 def yield_proc(name=nil, &block) @__event_loop__.new_yield_proc(name=nil, &block) end |