Asynchronous programming#

Futures#

template<typename T>
class Future#

EXPERIMENTAL A std::future-like class with more functionality.

A Future represents the results of a past or future computation. The Future API has two sides: a producer side and a consumer side.

The producer API allows creating a Future and setting its result or status, possibly after running a computation function.

The consumer API allows querying a Future’s current state, wait for it to complete, and composing futures with callbacks.

Public Functions

inline FutureState state() const#

Return the Future’s current state.

A return value of PENDING is only indicative, as the Future can complete concurrently. A return value of FAILURE or SUCCESS is definitive, though.

inline bool is_finished() const#

Whether the Future is finished.

A false return value is only indicative, as the Future can complete concurrently. A true return value is definitive, though.

inline const Result<ValueType> &result() const &#

Wait for the Future to complete and return its Result.

inline Result<ValueType> &&MoveResult()#

Returns an rvalue to the result.

This method is potentially unsafe

The future is not the unique owner of the result, copies of a future will also point to the same result. You must make sure that no other copies of the future exist. Attempts to add callbacks after you move the result will result in undefined behavior.

inline const Status &status() const#

Wait for the Future to complete and return its Status.

inline explicit operator Future() const#

Future<T> is convertible to Future<>, which views only the Status of the original.

Marking the returned Future Finished is not supported.

inline void Wait() const#

Wait for the Future to complete.

inline bool Wait(double seconds) const#

Wait for the Future to complete, or for the timeout to expire.

true is returned if the Future completed, false if the timeout expired. Note a false value is only indicative, as the Future can complete concurrently.

inline void MarkFinished(Result<ValueType> res)#

Producer API: mark Future finished.

The Future’s result is set to res.

template<typename E = ValueType, typename = typename std::enable_if<std::is_same<E, internal::Empty>::value>::type>
inline void MarkFinished(Status s = Status::OK())#

Mark a Future<> completed with the provided Status.

template<typename OnComplete, typename Callback = WrapOnComplete<OnComplete>>
inline void AddCallback(OnComplete on_complete, CallbackOptions opts = CallbackOptions::Defaults()) const#

Consumer API: Register a callback to run when this future completes.

The callback should receive the result of the future (const Result<T>&) For a void or statusy future this should be (const Status&)

There is no guarantee to the order in which callbacks will run. In particular, callbacks added while the future is being marked complete may be executed immediately, ahead of, or even the same time as, other callbacks that have been previously added.

WARNING: callbacks may hold arbitrary references, including cyclic references. Since callbacks will only be destroyed after they are invoked, this can lead to memory leaks if a Future is never marked finished (abandoned):

{ auto fut = Future<>::Make(); fut.AddCallback([fut]() {}); }

In this example fut falls out of scope but is not destroyed because it holds a cyclic reference to itself through the callback.

template<typename CallbackFactory, typename OnComplete = detail::result_of_t<CallbackFactory()>, typename Callback = WrapOnComplete<OnComplete>>
inline bool TryAddCallback(CallbackFactory callback_factory, CallbackOptions opts = CallbackOptions::Defaults()) const#

Overload of AddCallback that will return false instead of running synchronously.

This overload will guarantee the callback is never run synchronously. If the future is already finished then it will simply return false. This can be useful to avoid stack overflow in a situation where you have recursive Futures. For an example see the Loop function

Takes in a callback factory function to allow moving callbacks (the factory function will only be called if the callback can successfully be added)

Returns true if a callback was actually added and false if the callback failed to add because the future was marked complete.

template<typename OnSuccess, typename OnFailure = PassthruOnFailure<OnSuccess>, typename OnComplete = ThenOnComplete<OnSuccess, OnFailure>, typename ContinuedFuture = typename OnComplete::ContinuedFuture>
inline ContinuedFuture Then(OnSuccess on_success, OnFailure on_failure = {}, CallbackOptions options = CallbackOptions::Defaults()) const#

Consumer API: Register a continuation to run when this future completes.

The continuation will run in the same thread that called MarkFinished (whatever callback is registered with this function will run before MarkFinished returns). Avoid long-running callbacks in favor of submitting a task to an Executor and returning the future.

Two callbacks are supported:

  • OnSuccess, called with the result (const ValueType&) on successful completion. for an empty future this will be called with nothing ()

  • OnFailure, called with the error (const Status&) on failed completion. This callback is optional and defaults to a passthru of any errors.

Then() returns a Future whose ValueType is derived from the return type of the callbacks. If a callback returns:

  • void, a Future<> will be returned which will completes successfully as soon as the callback runs.

  • Status, a Future<> will be returned which will complete with the returned Status as soon as the callback runs.

  • V or Result<V>, a Future<V> will be returned which will complete with the result of invoking the callback as soon as the callback runs.

  • Future<V>, a Future<V> will be returned which will be marked complete when the future returned by the callback completes (and will complete with the same result).

The continued Future type must be the same for both callbacks.

Note that OnFailure can swallow errors, allowing continued Futures to successfully complete even if this Future fails.

If this future is already completed then the callback will be run immediately and the returned future may already be marked complete.

See AddCallback for general considerations when writing callbacks.

inline Future(ValueType val)#

Implicit constructor to create a finished future from a value.

inline Future(Result<ValueType> res)#

Implicit constructor to create a future from a Result, enabling use of macros like ARROW_ASSIGN_OR_RAISE.

inline Future(Status s)#

Implicit constructor to create a future from a Status, enabling use of macros like ARROW_RETURN_NOT_OK.

Public Static Functions

static inline Future Make()#

Producer API: instantiate a valid Future.

The Future’s state is initialized with PENDING. If you are creating a future with this method you must ensure that future is eventually completed (with success or failure). Creating a future, returning it, and never completing the future can lead to memory leaks (for example, see Loop).

static inline Future<ValueType> MakeFinished(Result<ValueType> res)#

Producer API: instantiate a finished Future.

template<typename E = ValueType, typename = typename std::enable_if<std::is_same<E, internal::Empty>::value>::type>
static inline Future MakeFinished(Status s = Status::OK())#

Make a finished Future<> with the provided Status.

template<typename OnSuccess>
struct PassthruOnFailure#
template<typename OnSuccess, typename OnFailure>
struct ThenOnComplete#
struct DummyOnSuccess#
struct WrapResultOnComplete#
template<typename OnComplete>
struct Callback#
struct WrapStatusyOnComplete#
template<typename OnComplete>
struct Callback#
template<typename T>
static Future<T> DeferNotOk(Result<Future<T>> maybe_future)#

If a Result<Future> holds an error instead of a Future, construct a finished Future holding that error.

template<typename T>
Future<std::vector<Result<T>>> All(std::vector<Future<T>> futures)#

Create a Future which completes when all of futures complete.

The future’s result is a vector of the results of futures. Note that this future will never be marked “failed”; failed results will be stored in the result vector alongside successful results.

Future AllComplete(const std::vector<Future<>> &futures)#

Create a Future which completes when all of futures complete.

The future will be marked complete if all futures complete successfully. Otherwise, it will be marked failed with the status of the first failing future.

Future AllFinished(const std::vector<Future<>> &futures)#

Create a Future which completes when all of futures complete.

The future will finish with an ok status if all futures finish with an ok status. Otherwise, it will be marked failed with the status of one of the failing futures.

Unlike AllComplete this Future will not complete immediately when a failure occurs. It will wait until all futures have finished.