proxygen
|
#include <Future-pre.h>
Public Member Functions | |
Promise () | |
~Promise () | |
Promise (Promise const &)=delete | |
Promise & | operator= (Promise const &)=delete |
Promise (Promise< T > &&other) noexcept | |
Promise & | operator= (Promise< T > &&other) noexcept |
SemiFuture< T > | getSemiFuture () |
Future< T > | getFuture () |
void | setException (exception_wrapper ew) |
template<class E > | |
std::enable_if< std::is_base_of< std::exception, E >::value >::type | setException (E const &e) |
template<typename F > | |
void | setInterruptHandler (F &&fn) |
template<class B = T> | |
std::enable_if< std::is_same< Unit, B >::value, void >::type | setValue () |
template<class M > | |
void | setValue (M &&value) |
void | setTry (Try< T > &&t) |
template<class F > | |
void | setWith (F &&func) |
bool | valid () const noexcept |
bool | isFulfilled () const noexcept |
Static Public Member Functions | |
static Promise< T > | makeEmpty () noexcept |
Private Types | |
using | Core = futures::detail::Core< T > |
Private Member Functions | |
Core & | getCore () |
Core const & | getCore () const |
Promise (futures::detail::EmptyConstruct) noexcept | |
void | throwIfFulfilled () const |
void | detach () |
Static Private Member Functions | |
template<typename CoreT > | |
static CoreT & | getCoreImpl (CoreT *core) |
Private Attributes | |
bool | retrieved_ |
Core * | core_ |
Friends | |
template<class > | |
class | futures::detail::FutureBase |
template<class > | |
class | SemiFuture |
template<class > | |
class | Future |
template<class , class > | |
class | futures::detail::CoreCallbackState |
Promises and futures provide a potentially nonblocking mechanism to execute a producer/consumer operation concurrently, with threading/pools controlled via an executor. There are multiple potential patterns for using promises and futures including some that block the caller, though that is discouraged; it should be used only when necessary.
One typical pattern uses a series of calls to set up a small, limited program that...
That usage pattern looks roughly like this:
auto [p, f] = makePromiseContract(executor); g = std::move(f).then([](MyValue&& x) { ...executor runs this code if/when a MyValue is ready... }); ...launch the async producer that eventually calls p.setResult()...
This is just one of many potential usage patterns. It has the desired property of being nonblocking to the caller. Of course the .then()
code is deferred until the produced value (or exception) is ready, but no code actually blocks pending completion of other operations.
The promise/future mechanism is limited to a single object of some arbitrary type. It also supports a (logically) void result, i.e., in cases where the continuation/consumer (the .then()
code if using the above pattern) is not expecting a value because the 'producer' is running for its side-effects.
The primary data movement is from producer to consumer, however Promise and Future also provide a mechanism where the consumer can send an interruption message to the producer. The meaning and response to that interruption message is controlled by the promise; see Promise::setInterruptHandler()
.
Neither Promise nor Future is thread-safe. All internal interactions between a promise and its associated future are thread-safe, provided that callers otherwise honor the promise's contract and the future's contract.
Logically there are up to three threads (though in practice there are often fewer - one thread might take on more than one role):
.then
or to a variant).For description purposes, the term 'shared state' is used to describe the logical state shared by the promise and the future. This 'third object' represents things like whether the result has been fulfilled, the value or exception in that result, and the data needed to handle interruption requests.
A promise can be in various logical states:
A promise p
may optionally have an associated future. This future, if it exists, may be either a SemiFuture or a Future, and is defined as the future (if any) that holds the same shared state as promise p
. The associated future is initially the future returned from p.getFuture()
or p.getSemiFuture()
, but various operations may transfer the shared state from one future to another.
Definition at line 23 of file Future-pre.h.
|
private |
folly::Promise< T >::Promise | ( | ) |
Constructs a valid but unfulfilled promise.
Postconditions:
valid() == true
(it will have a shared state)isFulfilled() == false
(its shared state won't have a result) Definition at line 45 of file Promise-inl.h.
folly::Promise< T >::~Promise | ( | ) |
Postconditions:
valid()
and !isFulfilled()
, the associated future (if any) will be completed with a BrokenPromise
exception as if by setException(...)
.valid()
, releases, possibly destroying, the shared state. Definition at line 72 of file Promise-inl.h.
References folly::Promise< T >::detach().
|
delete |
|
noexcept |
Move ctor
Postconditions:
this
will have whatever shared-state was previously held by other
(if any)other.valid()
will be false (other
will not have any shared state) Definition at line 48 of file Promise-inl.h.
|
explicitprivatenoexcept |
Definition at line 68 of file Promise-inl.h.
|
private |
Definition at line 77 of file Promise-inl.h.
References folly::Promise< T >::core_, folly::futures::detail::coreDetachPromiseMaybeWithResult(), folly::futures::detail::Core< T >::detachFuture(), and folly::Promise< T >::retrieved_.
Referenced by folly::Promise< T >::operator=(), and folly::Promise< T >::~Promise().
|
inlineprivate |
Definition at line 421 of file Promise.h.
Referenced by folly::Promise< T >::getSemiFuture(), folly::Promise< T >::setInterruptHandler(), and folly::Promise< T >::throwIfFulfilled().
|
inlineprivate |
|
inlinestaticprivate |
Future< T > folly::Promise< T >::getFuture | ( | ) |
Return a Future associated with this Promise, sharing the same shared state as this
.
Preconditions:
valid() == true
(else throws PromiseInvalid)this
Promise (else throws FutureAlreadyRetrieved)Postconditions:
RESULT.valid() == true
this
DEPRECATED: use folly::makePromiseContract()
instead. If you can't use that, use this->getSemiFuture()
then get a Future by calling .via()
with an appropriate executor.
Definition at line 97 of file Promise-inl.h.
References folly::Promise< T >::getSemiFuture(), folly::InlineExecutor::instance(), type, and value.
Referenced by folly::fibers::BatchDispatcher< ValueT, ResultT, ExecutorT >::add(), folly::FutureExecutor< ExecutorImpl >::addFuture(), folly::fibers::FiberManager::addTaskFuture(), folly::fibers::FiberManager::addTaskRemoteFuture(), wangle::TimekeeperTester::after(), wangle::TimekeeperTester::at(), BENCHMARK_RELATIVE(), wangle::ClientBootstrap< DefaultPipeline >::connect(), fGen(), folly::python::test::future_getValueX5(), folly::AttachDetachClient::getFuture(), wangle::PipelinedClientDispatcher< Pipeline, Req, Resp >::operator()(), HTTPDownstreamTest< SPDY3_1CodecPair >::sendRequestLater(), TEST(), TEST_F(), fizz::server::test::TEST_F(), fizz::test::TEST_F(), and folly::unorderedReduce().
SemiFuture< T > folly::Promise< T >::getSemiFuture | ( | ) |
Return a SemiFuture associated with this Promise, sharing the same shared state as this
.
Preconditions:
valid() == true
(else throws PromiseInvalid)this
Promise (else throws FutureAlreadyRetrieved)Postconditions:
RESULT.valid() == true
this
DEPRECATED: use folly::makePromiseContract()
instead.
Definition at line 88 of file Promise-inl.h.
References folly::Promise< T >::getCore(), and folly::Promise< T >::retrieved_.
Referenced by folly::futures::detail::chainExecutor(), folly::collectAny(), folly::Promise< T >::getFuture(), folly::Future< T >::onError(), folly::Future< T >::onTimeout(), TEST(), folly::futures::detail::FutureBase< T >::thenImplementation(), folly::Future< T >::via(), folly::SemiFuture< T >::wait(), and folly::futures::detail::waitImpl().
|
noexcept |
True if either this promise was fulfilled or is invalid.
!valid()
valid()
and this was fulfilled (a prior call to setValue()
, setTry()
, setException()
, or setWith()
) Definition at line 143 of file Promise-inl.h.
References folly::Promise< T >::core_, and folly::futures::detail::Core< T >::hasResult().
Referenced by TEST().
|
staticnoexcept |
Returns an invalid promise.
Postconditions:
RESULT.valid() == false
RESULT.isFulfilled() == true
Definition at line 40 of file Promise-inl.h.
Referenced by TEST().
|
delete |
Move assignment
Postconditions:
valid()
and !isFulfilled()
, the associated future (if any) will be completed with a BrokenPromise
exception as if by setException(...)
.valid()
, releases, possibly destroying, the original shared state.this
will have whatever shared-state was previously held by other
(if any)other.valid()
will be false (other
will not have any shared state) Definition at line 53 of file Promise-inl.h.
References folly::Promise< T >::core_, folly::Promise< T >::detach(), folly::exchange(), and folly::Promise< T >::retrieved_.
void folly::Promise< T >::setException | ( | exception_wrapper | ew | ) |
Fulfill the Promise with an exception_wrapper.
Sample usage:
Promise<MyValue> p = ... ... auto const ep = std::exception_ptr(); auto const ew = exception_wrapper::from_exception_ptr(ep); p.setException(ew);
Functionally equivalent to setTry(Try<T>(std::move(ew)))
Preconditions:
valid() == true
(else throws PromiseInvalid)isFulfilled() == false
(else throws PromiseAlreadySatisfied)Postconditions:
isFulfilled() == true
valid() == true
(unchanged)Definition at line 111 of file Promise-inl.h.
References folly::gen::move, and folly::Promise< T >::setTry().
Referenced by folly::AttachDetachClient::readErr(), folly::Promise< T >::setException(), TEST(), TEST_F(), and wangle::AsyncSocketHandler::WriteCallback::writeErr().
std::enable_if< std::is_base_of< std::exception, E >::value >::type folly::Promise< T >::setException | ( | E const & | e | ) |
Fulfill the Promise with exception e
as if by setException(make_exception_wrapper<E>(e))
.
Please see setException(exception_wrapper)
for semantics/contract.
Definition at line 106 of file Promise-inl.h.
References folly::Promise< T >::setException().
Sets a handler for the producer to receive a (logical) interruption request (exception) sent from the consumer via future.raise()
.
Details: The consumer calls future.raise()
when it wishes to send a logical interruption message (an exception), and that exception/message is passed to fn()
. The thread used to call fn()
depends on timing (see Postconditions for threading details).
Handler fn()
can do anything you want, but if you bother to set one then you probably will want to (more or less immediately) fulfill the promise with an exception (or other special value) indicating how the interrupt was handled.
This call silently does nothing if isFulfilled()
.
Preconditions:
valid() == true
(else throws PromiseInvalid)fn
must be copyable and must be invocable with exception_wrapper const&
fn()
must be safe to run either synchronously within the setInterruptHandler()
call or asynchronously within the consumer thread's call to future.raise()
.fn()
must also be safe to run after this promise is fulfilled; this may have lifetime/race-case ramifications, e.g., if the code of fn()
might access producer-resources that will be destroyed, then the destruction of those producer-resources must be deferred beyond the moment when this promise is fulfilled.Postconditions:
future.raise()
early enough (up to a particular moment within the setInterruptHandler()
call), fn()
will be called synchronously (in the current thread, during this call).future.raise()
after that moment within setInterruptHandler()
but before this promise is fulfilled, fn()
will be called asynchronously (in the consumer's thread, within the call to future.raise()
).future.raise()
after this promise is fulfilled, fn()
may or may not be called at all, and if it is called, it will be called asynchronously (within the consumer's call to future.raise()
).IMPORTANT: fn()
should return quickly since it could block this call to promise.setInterruptHandler()
and/or a concurrent call to future.raise()
. Those two functions contend on the same lock; those calls could block if fn()
is invoked within one of those while the lock is held.
Definition at line 117 of file Promise-inl.h.
References folly::Promise< T >::getCore(), and folly::futures::detail::Core< T >::setInterruptHandler().
Referenced by TEST().
void folly::Promise< T >::setTry | ( | Try< T > && | t | ) |
Fulfill the Promise with the specified Try (value or exception).
Preconditions:
valid() == true
(else throws PromiseInvalid)isFulfilled() == false
(else throws PromiseAlreadySatisfied)Postconditions:
isFulfilled() == true
valid() == true
(unchanged)Definition at line 122 of file Promise-inl.h.
References folly::Promise< T >::core_, folly::gen::move, folly::futures::detail::Core< T >::setResult(), folly::pushmi::detail::t, and folly::Promise< T >::throwIfFulfilled().
Referenced by folly::FutureExecutor< ExecutorImpl >::addFuture(), folly::fibers::FiberManager::addTaskFuture(), folly::fibers::FiberManager::addTaskRemoteFuture(), folly::Future< T >::onTimeout(), folly::Promise< T >::setException(), folly::Promise< T >::setValue(), folly::Promise< T >::setWith(), TEST(), folly::Future< T >::via(), and folly::futures::detail::waitImpl().
|
inline |
Fulfills a (logically) void Promise, that is, Promise<Unit>. (If you want a void-promise, use Promise<Unit>, not Promise<void>.)
Preconditions:
valid() == true
(else throws PromiseInvalid)isFulfilled() == false
(else throws PromiseAlreadySatisfied)Postconditions:
isFulfilled() == true
valid() == true
(unchanged) Definition at line 326 of file Promise.h.
Referenced by BENCHMARK_RELATIVE(), fGen(), folly::AttachDetachClient::readDataAvailable(), TEST(), TEST_F(), fizz::server::test::TEST_F(), fizz::test::TEST_F(), and wangle::AsyncSocketHandler::WriteCallback::writeSuccess().
Fulfill the Promise with the specified value using perfect forwarding.
Functionally equivalent to setTry(Try<T>(std::forward<M>(value)))
Preconditions:
valid() == true
(else throws PromiseInvalid)isFulfilled() == false
(else throws PromiseAlreadySatisfied)Postconditions:
isFulfilled() == true
valid() == true
(unchanged)Definition at line 129 of file Promise-inl.h.
References folly::Promise< T >::setTry(), and value.
Fulfill this Promise with the result of a function that takes no arguments and returns something implicitly convertible to T.
Example:
p.setWith([] { do something that may throw; return a T; });
Functionally equivalent to setTry(makeTryWith(static_cast<F&&>(func)));
Preconditions:
valid() == true
(else throws PromiseInvalid)isFulfilled() == false
(else throws PromiseAlreadySatisfied)Postconditions:
func()
will be run synchronously (in this thread, during this call)func()
returns, the return value will be captured as if via setValue()
func()
throws, the exception will be captured as if via setException()
isFulfilled() == true
valid() == true
(unchanged)Definition at line 137 of file Promise-inl.h.
References folly::makeTryWith(), folly::Promise< T >::setTry(), and folly::Promise< T >::throwIfFulfilled().
Referenced by folly::FutureExecutor< ExecutorImpl >::addFuture(), folly::python::test::future_getValueX5(), and TEST().
|
private |
Definition at line 61 of file Promise-inl.h.
References folly::Promise< T >::getCore().
Referenced by folly::Promise< T >::setTry(), and folly::Promise< T >::setWith().
|
inlinenoexcept |
true if this has a shared state; false if this has been consumed/moved-out.
|
private |
Definition at line 438 of file Promise.h.
Referenced by folly::futures::detail::chainExecutor(), folly::Promise< T >::detach(), folly::Promise< T >::isFulfilled(), folly::Future< T >::onError(), folly::Promise< T >::operator=(), folly::Promise< T >::setTry(), and folly::futures::detail::FutureBase< T >::thenImplementation().
|
private |
Definition at line 412 of file Promise.h.
Referenced by folly::Promise< T >::detach(), folly::Promise< T >::getSemiFuture(), and folly::Promise< T >::operator=().