Class: Concurrent::IVar
- Inherits:
-
Synchronization::LockableObject
- Object
- Synchronization::LockableObject
- Concurrent::IVar
- Includes:
- Concern::Obligation, Concern::Observable
- Defined in:
- lib/concurrent-ruby/concurrent/ivar.rb
Overview
An IVar
is like a future that you can assign. As a future is a value that
is being computed that you can wait on, an IVar
is a value that is waiting
to be assigned, that you can wait on. IVars
are single assignment and
deterministic.
Then, express futures as an asynchronous computation that assigns an IVar
.
The IVar
becomes the primitive on which futures and
dataflow are built.
An IVar
is a single-element container that is normally created empty, and
can only be set once. The I in IVar
stands for immutable. Reading an
IVar
normally blocks until it is set. It is safe to set and read an IVar
from different threads.
If you want to have some parallel task set the value in an IVar
, you want
a Future
. If you want to create a graph of parallel tasks all executed
when the values they depend on are ready you want dataflow
. IVar
is
generally a low-level primitive.
Examples
Create, set and get an IVar
ivar = Concurrent::IVar.new
ivar.set 14
ivar.value #=> 14
ivar.set 2 # would now be an error
See Also
- For the theory: Arvind, R. Nikhil, and K. Pingali. I-Structures: Data structures for parallel computing. In Proceedings of Workshop on Graph Reduction, 1986.
- For recent application: DataDrivenFuture in Habanero Java from Rice.
Direct Known Subclasses
Instance Method Summary collapse
-
#add_observer(observer = nil, func = :update, &block) ⇒ undocumented
Add an observer on this object that will receive notification on update.
-
#fail(reason = StandardError.new) ⇒ IVar
Set the
IVar
to failed due to some error and wake or notify all threads waiting on it. -
#initialize(value = NULL, opts = {}, &block) ⇒ IVar
constructor
Create a new
IVar
in the:pending
state with the (optional) initial value. -
#set(value = NULL) { ... } ⇒ IVar
Set the
IVar
to a value and wake or notify all threads waiting on it. -
#try_set(value = NULL) { ... } ⇒ Boolean
Attempt to set the
IVar
with the given value or block. -
#complete? ⇒ Boolean
included
from Concern::Obligation
Has the obligation completed processing?.
-
#count_observers ⇒ Integer
included
from Concern::Observable
Return the number of observers associated with this object.
-
#delete_observer(observer) ⇒ Object
included
from Concern::Observable
Remove
observer
as an observer on this object so that it will no longer receive notifications. -
#delete_observers ⇒ Observable
included
from Concern::Observable
Remove all observers associated with this object.
- #exception(*args) ⇒ undocumented included from Concern::Obligation
-
#fulfilled? ⇒ Boolean
(also: #realized?)
included
from Concern::Obligation
Has the obligation been fulfilled?.
-
#incomplete? ⇒ Boolean
included
from Concern::Obligation
Is the obligation still awaiting completion of processing?.
-
#pending? ⇒ Boolean
included
from Concern::Obligation
Is obligation completion still pending?.
-
#reason ⇒ Exception
included
from Concern::Obligation
If an exception was raised during processing this will return the exception object.
-
#rejected? ⇒ Boolean
included
from Concern::Obligation
Has the obligation been rejected?.
-
#state ⇒ Symbol
included
from Concern::Obligation
The current state of the obligation.
-
#unscheduled? ⇒ Boolean
included
from Concern::Obligation
Is the obligation still unscheduled?.
-
#value(timeout = nil) ⇒ Object
included
from Concern::Obligation
The current value of the obligation.
-
#value!(timeout = nil) ⇒ Object
included
from Concern::Obligation
The current value of the obligation.
-
#wait(timeout = nil) ⇒ Obligation
included
from Concern::Obligation
Wait until obligation is complete or the timeout has been reached.
-
#wait!(timeout = nil) ⇒ Obligation
(also: #no_error!)
included
from Concern::Obligation
Wait until obligation is complete or the timeout is reached.
-
#with_observer(observer = nil, func = :update, &block) ⇒ Observable
included
from Concern::Observable
As
#add_observer
but can be used for chaining.
Constructor Details
#initialize(value = NULL, opts = {}, &block) ⇒ IVar
Create a new IVar
in the :pending
state with the (optional) initial value.
61 62 63 64 65 66 67 |
# File 'lib/concurrent-ruby/concurrent/ivar.rb', line 61 def initialize(value = NULL, opts = {}, &block) if value != NULL && block_given? raise ArgumentError.new('provide only a value or a block') end super(&nil) synchronize { ns_initialize(value, opts, &block) } end |
Instance Method Details
#add_observer(observer = nil, func = :update, &block) ⇒ undocumented
Add an observer on this object that will receive notification on update.
Upon completion the IVar
will notify all observers in a thread-safe way.
The func
method of the observer will be called with three arguments: the
Time
at which the Future
completed the asynchronous operation, the
final value
(or nil
on rejection), and the final reason
(or nil
on
fulfillment).
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/concurrent-ruby/concurrent/ivar.rb', line 80 def add_observer(observer = nil, func = :update, &block) raise ArgumentError.new('cannot provide both an observer and a block') if observer && block direct_notification = false if block observer = block func = :call end synchronize do if event.set? direct_notification = true else observers.add_observer(observer, func) end end observer.send(func, Time.now, self.value, reason) if direct_notification observer end |
#fail(reason = StandardError.new) ⇒ IVar
Set the IVar
to failed due to some error and wake or notify all threads waiting on it.
134 135 136 |
# File 'lib/concurrent-ruby/concurrent/ivar.rb', line 134 def fail(reason = StandardError.new) complete(false, nil, reason) end |
#set(value = NULL) { ... } ⇒ IVar
Set the IVar
to a value and wake or notify all threads waiting on it.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/concurrent-ruby/concurrent/ivar.rb', line 112 def set(value = NULL) check_for_block_or_value!(block_given?, value) raise MultipleAssignmentError unless compare_and_set_state(:processing, :pending) begin value = yield if block_given? complete_without_notification(true, value, nil) rescue => ex complete_without_notification(false, nil, ex) end notify_observers(self.value, reason) self end |
#try_set(value = NULL) { ... } ⇒ Boolean
Attempt to set the IVar
with the given value or block. Return a
boolean indicating the success or failure of the set operation.
144 145 146 147 148 149 |
# File 'lib/concurrent-ruby/concurrent/ivar.rb', line 144 def try_set(value = NULL, &block) set(value, &block) true rescue MultipleAssignmentError false end |
#complete? ⇒ Boolean Originally defined in module Concern::Obligation
Has the obligation completed processing?
#count_observers ⇒ Integer Originally defined in module Concern::Observable
Return the number of observers associated with this object.
#delete_observer(observer) ⇒ Object Originally defined in module Concern::Observable
Remove observer
as an observer on this object so that it will no
longer receive notifications.
#delete_observers ⇒ Observable Originally defined in module Concern::Observable
Remove all observers associated with this object.
#exception(*args) ⇒ undocumented Originally defined in module Concern::Obligation
#fulfilled? ⇒ Boolean Also known as: realized? Originally defined in module Concern::Obligation
Has the obligation been fulfilled?
#incomplete? ⇒ Boolean Originally defined in module Concern::Obligation
Is the obligation still awaiting completion of processing?
#pending? ⇒ Boolean Originally defined in module Concern::Obligation
Is obligation completion still pending?
#reason ⇒ Exception Originally defined in module Concern::Obligation
If an exception was raised during processing this will return the
exception object. Will return nil
when the state is pending or if
the obligation has been successfully fulfilled.
#rejected? ⇒ Boolean Originally defined in module Concern::Obligation
Has the obligation been rejected?
#state ⇒ Symbol Originally defined in module Concern::Obligation
The current state of the obligation.
#unscheduled? ⇒ Boolean Originally defined in module Concern::Obligation
Is the obligation still unscheduled?
#value(timeout = nil) ⇒ Object Originally defined in module Concern::Obligation
The current value of the obligation. Will be nil
while the state is
pending or the operation has been rejected.
#value!(timeout = nil) ⇒ Object Originally defined in module Concern::Obligation
The current value of the obligation. Will be nil
while the state is
pending or the operation has been rejected. Will re-raise any exceptions
raised during processing (but will not raise an exception on timeout).
#wait(timeout = nil) ⇒ Obligation Originally defined in module Concern::Obligation
Wait until obligation is complete or the timeout has been reached.
#wait!(timeout = nil) ⇒ Obligation Also known as: no_error! Originally defined in module Concern::Obligation
Wait until obligation is complete or the timeout is reached. Will re-raise any exceptions raised during processing (but will not raise an exception on timeout).
#with_observer(observer = nil, func = :update, &block) ⇒ Observable Originally defined in module Concern::Observable
As #add_observer
but can be used for chaining.