.atomically ⇒ undocumented

Run a block that reads and writes TVars as a single atomic transaction.
With respect to the value of TVar objects, the transaction is atomic, in
that it either happens or it does not, consistent, in that the TVar
objects involved will never enter an illegal state, and isolated, in that
transactions never interfere with each other. You may recognise these
properties from database transactions.

There are some very important and unusual semantics that you must be aware of:

Most importantly, the block that you pass to atomically may be executed
more than once. In most cases your code should be free of
side-effects, except for via TVar.

If an exception escapes an atomically block it will abort the transaction.

It is undefined behaviour to use callcc or Fiber with atomically.

If you create a new thread within an atomically, it will not be part of
the transaction. Creating a thread counts as a side-effect.

Transactions within transactions are flattened to a single transaction.

# File 'lib/concurrent/tvar.rb', line 93defatomicallyraiseArgumentError.new('no block given')unlessblock_given?# Get the current transaction
transaction=Transaction::current# Are we not already in a transaction (not nested)?
iftransaction.nil?# New transaction
begin# Retry loop
loopdo# Create a new transaction
transaction=Transaction.newTransaction::current=transaction# Run the block, aborting on exceptions
beginresult=yieldrescueTransaction::AbortError=>etransaction.abortresult=Transaction::ABORTEDrescueTransaction::LeaveError=>etransaction.abortbreakresultrescue=>etransaction.abortraiseeend# If we can commit, break out of the loop
ifresult!=Transaction::ABORTEDiftransaction.commitbreakresultendendendensure# Clear the current transaction
Transaction::current=nilendelse# Nested transaction - flatten it and just run the block
yieldendend

.dataflow(*inputs) {|inputs| ... } ⇒ Object

Dataflow allows you to create a task that will be scheduled when all of its data dependencies are available.
Data dependencies are Future values. The dataflow task itself is also a Future value, so you can build up a graph of these tasks, each of which is run when all the data and other tasks it depends on are available or completed.

Our syntax is somewhat related to that of Akka's flow and Habanero Java's DataDrivenFuture. However unlike Akka we don't schedule a task at all until it is ready to run, and unlike Habanero Java we pass the data values into the task instead of dereferencing them again in the task.

The theory of dataflow goes back to the 70s. In the terminology of the literature, our implementation is coarse-grained, in that each task can be many instructions, and dynamic in that you can create more tasks within other tasks.

Example

A dataflow task is created with the dataflow method, passing in a block.

This produces a simple Future value. The task will run immediately, as it has no dependencies. We can also specify Future values that must be available before a task will run. When we do this we get the value of those futures passed to our block.

Using the dataflow method you can build up a directed acyclic graph (DAG) of tasks that depend on each other, and have the tasks run as soon as their dependencies are ready and there is CPU capacity to schedule them. This can help you create a program that uses more of the CPU resources available to you.

Derivation

This section describes how we could derive dataflow from other primitives in this library.

One of the drawbacks of this approach is that all the futures start, and then most of them immediately block on their dependencies. We know that there's no point executing those futures until their dependencies are ready, so let's not execute each future until all their dependencies are ready.

To do this we'll create an object that counts the number of times it observes a future finishing before it does something - and for us that something will be to execute the next future.

Since we know that the futures the dataflow computation depends on are already going to be available when the future is executed, we might as well pass the values into the block so we don't have to reference the futures inside the block. This allows us to write the dataflow block as straight non-concurrent code without reference to futures.

.dataflow_with!(executor, *inputs, &block) ⇒ undocumented

.disable_at_exit_handlers! ⇒ undocumented

Note:

this option should be needed only because of at_exit ordering
issues which may arise when running some of the testing frameworks.
E.g. Minitest's test-suite runs itself in at_exit callback which
executes after the pools are already terminated. Then auto termination
needs to be disabled and called manually after test-suite ends.

Note:

This method should never be called
from within a gem. It should only be used from within the main
application and even then it should be used only when necessary.

Disables AtExit handlers including pool auto-termination handlers.
When disabled it will be the application programmer's responsibility
to ensure that the handlers are shutdown properly prior to application
exit by calling AtExitImplementation.new.install.run method.

.monotonic_time ⇒ Float

Note:

Time calculations on all platforms and languages are sensitive to
changes to the system clock. To alleviate the potential problems
associated with changing the system clock while an application is running,
most modern operating systems provide a monotonic clock that operates
independently of the system clock. A monotonic clock cannot be used to
determine human-friendly clock times. A monotonic clock is used exclusively
for calculating time intervals. Not all Ruby platforms provide access to an
operating system monotonic clock. On these platforms a pure-Ruby monotonic
clock will be used as a fallback. An operating system monotonic clock is both
faster and more reliable than the pure-Ruby implementation. The pure-Ruby
implementation should be fast and reliable enough for most non-realtime
operations. At this time the common Ruby platforms that provide access to an
operating system monotonic clock are MRI 2.1 and above and JRuby (all versions).

Returns the current time a tracked by the application monotonic clock.