The promise and future concepts allow one to provide a result asynchronously. The implementor creates a promise for the result and returns the future contained in the promise. The caller can then use the result of the future later.
You can see a complete usage example at the end of this document.
Global Namespaces
namespace qi
Classes (namespace qi)
class qi::Future
Functions (class qi::Future)
class qi::Promise
Functions (class qi::Promise)
class qi::FutureSync
Functions (class qi::FutureSync)
Functions (namespace qi)
A Future
provides a way to wait for and get the result of an asynchronous
operation. It is the receiving end of a qi::Future
- qi::Promise
pair.
Future is templated by the type of the underlying value. void is permitted.
A future can be in multiple states represented by FutureState
:
There are multiple ways to handle a future. The first is to use the
qi::Future<T>::value
method. In that case, the call will block until the
Future leaves the running state. Then if a value if available, it will be
returned. Otherwise a FutureException
will be raised:
qi::Future<int> someOperation();
int callIt()
{
int i = someOperation().value(); // wait, then get the value or throw
return i;
}
If you do not wish to wait forever, or want to handle Future error without
catching an exception, you can use Future<T>::wait
(timeout):
this function waits at most the specified time in milliseconds, and return
a FutureState
. You can then safely call Future<T>::value
or
Future<T>::error
, if future is in state FutureState_FinishedWithValue
or
FutureState_FinishedWithError
respectively:
qi::Future<int> f = someOperation();
switch(f.wait(1000))
{
case FutureState_Running:
std::cerr << "Still not ready" << std::endl;
break;
case FutureState_Canceled:
std::cerr << "Canceled" << std::endl;
break;
case FutureState_FinishedWithError:
std::cerr << "Error: " << f.error() << std::endl;
break;
case FutureState_FinishedWithValue:
std::cerr << "Value: " << f.value() << std::endl;
break;
}
Alternatively, you can get notified of Future completion asynchronously using
Future<T>::connect
. This function accepts a callback function or
functor with signature void (qi::Future<T> f)
.
The Future guarantees you that your callback function will be called once and only once, when or if the Future leaves the Running state (that is, enters one of Canceled, FinishedWithError or FinishedWithValue):
void myCallback(const qi::Future<int>& f)
{
qi::FutureState s = f.wait(); // will return immediately, Future has finished.
switch(s) {...}
}
// ...
qi::Future<int> f = someOperation();
f.connect(&myCallback);
connect() accepts extra arguments after the callback: values or placeholders
that will be bound to the call(similarly to how boost::bind
works). If
the first argument is a boost::weak_ptr
, or inherits from qi::Trackable
,
then the callback will not be called if the weak_ptr cannot be locked, or
if the Trackable was destroyed:
class Foo
{
public:
void onOpFinished(const qi::Future<int>& op, int opNumber);
};
void safe_async_op(boost::shared_ptr<Foo> foo, int opNumber)
{
qi::Future<int> future = someOperation();
// This version will keep foo alive at least until the Future finished
future.connect(&Foo::onOpFinished, foo, _1, opNumber);
// This version is safe in case foo is destroyed before the Future finishes.
future.connect(&Foo::onOpFinished, boost::weak_ptr<Foo>(foo), _1, opNumber);
}
The callback can be run in two modes that we call Sync and Async. Async means that the callback will be run in its own thread. Sync means one of the two:
There are two parameters that influence if the call will be Sync or Async. The algorithm is the following:
An async operation that returns a Future can support cancellation. To check if
a future you have can be canceled, use isCancelable
.
If isCancelable
returns true, you can try to abort the operation by calling
cancel
. Depending on the operation and on the timing of your call, your
cancel request might be ignored (for example, if it is received too late and a
value is already available). But you can expect the Future to hastily leave the
Running state one way or an other.
The property cancellable of a future is defined at the construction of the promise. You rarely need to check if a future is cancelable, as the specification of the function which returned it should tell whether it is cancelable or not.
A helper container, qi::ScopedFutureGroup
, can be used to manage a set of cancelable
futures that must be cancelled once the container is destroyed.
It helps managing automatically future cancelation when destroying a system which
is represented by a class.
A qi::Promise
is an object that can create and satisfy a qi::Future
.
Like Future, it has shared semantics (all copies of a Promise represent the
same object). The next example illustrates it’s basic use case:
qi::Future<int> myFunctionReturningAFuture()
{
qi::Promise<int> promise;
// start an asynchronous operation, holding the promise
// note that starting threads like that is bad practice, use qi::async
boost::thread(someAsynchronousOp, promise);
return promise.future();
}
void someAsynchronousOp(qi::Promise<int> promise)
{
try {
int result = performSomeTask();
promise.setValue(result);
}
catch(const std::exception& e)
{
promise.setError(e.what());
}
}
In plain English:
Promise
and return the future()
obtained with
Promise::future
.Promise::setValue
or
Promise::setError
.Promise
.If your asynchronous operation can be canceled, you must provide a callback
with signature void(qi::Promise<T>)
to the Promise
constructor. You can
provide qi::PromiseNoop
if you don’t have any specific action to do upon
cancellation.
This callback will then be called if a cancellation request is received by a
connected Future
. This callback is expected to ensure that the connected
Future
hastily leaves the Running state, by calling one of
Promise::setValue
, Promise::setError
and Promise::setCanceled
.
However this call does not have to be made synchronously in the cancellation
callback.
If you used qi::PromiseNoop
, you can rely on Promise::isCancelRequested
to
check at a given point if the user requested a cancellation.
You can see an example with cancellation support at the end of this document.
When one of the three state-changing functions listed above is called on a Promise, callbacks registered to the connected Future will be invoked. You can control whether this invocation is made synchronously, or asynchronously using a thread from an internal thread pool, by passing one of FutureCallbackType_Sync and FutureCallbackType_Async to the Promise constructor.
qi::FutureSync
is a lightweight wrapper on top of
qi::Future
that will wait on the Future
in its destructor
if the Future
was ignored by the user.
It is intended to be used as a way to provide a default apparent
synchronous-blocking behavior to a function, that can be changed into
an asynchronous behavior by handling the resulting FutureSync
.
You can simply change the returned type from Future
to FutureSync
in the
basic example. The returned Future
will transparently
convert to a FutureSync
.
FutureSync
follow this simple rule: The destructor will call
Future::wait
from its destructor, unless:
Future
or FutureSync
FutureSync::async
or any of the Future function is called (wait
,
connect
, ...)FutureSync
also has a cast operator that allows you to use the returned value
transparently.
qi::FutureSync<int> someFunction();
void test()
{
someFunction(); // will wait
qi::FutureSync<int> f = someFunction(); // will wait at end of scope
someFunction().async(); // will not wait
qi::Future<int> f2 = someFunction(); // will not wait
someFunction().value(); // will wait, because of value()
int val = someFunction(); // will wait, does the same as
// value(), may throw on error
}
Here is an example of an asynchronous function implementation that supports cancellation.
Let’s implement this class and make calculate()
asynchronous.
class Worker {
public:
int calculate();
};
First, calculate
must return a future and we must create a function to do
the actual work.
#include <qi/future.hpp>
class Worker {
public:
qi::Future<int> calculate();
private:
void doWork(qi::Promise<int> promise);
};
For the sake of this example, we’ll use a simple function to simulate work:
void Worker::doWork(qi::Promise<int> promise)
{
int acc = 0;
for (int i = 0; i < 100; ++i)
{
qi::os::msleep(10); // working...
acc += 1;
}
promise.setValue(acc);
}
And then, we must call this function asynchronously and return the corresponding future:
qi::Future<int> Worker::calculate() {
qi::Promise<int> promise;
qi::async(boost::bind(&Worker::doWork, this, promise));
return promise.future();
}
Now, calculate
is asynchronous! But this isn’t useful at all, our code is
more complex and this could have been done just by calling qi::async
. What we
can do now is to support cancellation so that one can call cancel()
on the
returned future to abort the action.
Promises are cancelable when they are given a cancellation callback at construction. You usually don’t need this callback so you can just pass the no-operation callback.
qi::Future<int> Worker::calculate() {
qi::Promise<int> promise(qi::PromiseNoop<int>);
qi::async(boost::bind(&Worker::doWork, this, promise));
return promise.future();
}
doWork()
can now check if the future has been cancelled.
void Worker::doWork(qi::Promise<int> promise)
{
int acc = 0;
for (int i = 0; i < 100; ++i)
{
if (promise.isCancelRequested())
{
std::cout << "cancel requested" << std::endl;
promise.setCanceled();
return;
}
qi::os::msleep(10); // working...
acc += 1;
}
promise.setValue(acc);
}
qi::FutureState
¶Name | Brief |
---|---|
FutureState_None |
Future is not tied to a promise. |
FutureState_Running |
Operation pending. |
FutureState_Canceled |
The future has been canceled. |
FutureState_FinishedWithError |
The operation is finished with an error. |
FutureState_FinishedWithValue |
The operation is finished with a value. |
Future
()Future
(const Future<T>& b)operator==
(const Future<T>& other) constoperator=
(const Future<T>& b)operator<
(const Future<T>& b) constuniqueId
() constisValid
() constFuture
(const ValueType& v, FutureCallbackType async)value
(int msecs) constoperator const ValueTypeCast&
() constwait
(int msecs) constwait
(qi::Duration duration) constwaitFor
(qi::Duration duration) constwait
(qi::SteadyClock::time_point timepoint) constwaitUntil
(qi::SteadyClock::time_point timepoint) constisFinished
() constisRunning
() constisCanceled
() consthasError
(int msecs) consthasValue
(int msecs) consterror
(int msecs) constsync
()cancel
()isCancelable
() constthenR
(FutureCallbackType type, AF&& func)thenR
(AF&& func)
()
()then
(FutureCallbackType type, AF&& func)then
(AF&& func)andThenR
(FutureCallbackType type, AF&& func)andThenR
(AF&& func)andThen
(FutureCallbackType type, AF&& func)andThen
(AF&& func)makeCanceler
()connect
(const AF& fun, FutureCallbackType type)connect
(FUNCTYPE fun, ARG0 tracked, ..., FutureCallbackType type)connectWithStrand
(qi::Strand* strand, const boost::function<void(const Future<T>&)>& cb)connectWithStrand
(qi::Strand& strand, const boost::function<void(const Future<T>&)>& cb)_connect
(const boost::function<void()>& s)impl
()Future
(boost::shared_ptr<detail::FutureBaseTyped<T>> p)Class that represents a value that will be set later in time.
qi::Future<T>::
Future
()¶qi::Future<T>::
Future
(const Future<T>& b)¶qi::Future<T>::
operator==
(const Future<T>& other) const
¶qi::Future<T>::
operator=
(const Future<T>& b)¶qi::Future<T>::
operator<
(const Future<T>& b) const
¶qi::Future<T>::
uniqueId
() const
¶qi::Future<T>::
isValid
() const
¶Brief:
Returns: | true if this future is associated to a promise, false otherwise. |
---|
qi::Future<T>::
Future
(const ValueType& v, FutureCallbackType async = FutureCallbackType_Auto)¶Construct a Future that already contains a value.
qi::Future<T>::
value
(int msecs = FutureTimeout_Infinite) const
¶Brief: Return the value associated to a Future.
Parameters: |
|
---|---|
Returns: | the value |
This function can throw for many reason: wait timeoutuser errorfuture canceled
if an error is set, then value throw a FutureUserException, others errors are FutureException.
qi::Future<T>::
operator
const ValueTypeCast&() const
¶same as value() with an infinite timeout.
qi::Future<T>::
wait
(int msecs = FutureTimeout_Infinite) const
¶Brief:
Parameters: |
|
---|---|
Returns: | a FutureState corresponding to the state of the future. |
Wait for future to contain a value or an error
qi::Future<T>::
wait
(qi::Duration duration) const
¶Brief:
Parameters: |
|
---|---|
Returns: | a FutureState corresponding to the state of the future. |
Wait for future to contain a value or an error
qi::Future<T>::
waitFor
(qi::Duration duration) const
¶qi::Future<T>::
wait
(qi::SteadyClock::time_point timepoint) const
¶Brief:
Parameters: |
|
---|---|
Returns: | a FutureState corresponding to the state of the future. |
Wait for future to contain a value or an error
qi::Future<T>::
waitUntil
(qi::SteadyClock::time_point timepoint) const
¶qi::Future<T>::
isFinished
() const
¶Brief:
Returns: | true if the future is finished do not throw |
---|
qi::Future<T>::
isRunning
() const
¶Brief:
Returns: | true if the future is running do not throw |
---|
qi::Future<T>::
isCanceled
() const
¶Brief:
Returns: | true if the future has been canceled This means that the future has been fully canceled, not that a cancel was requested. do not throw |
---|
qi::Future<T>::
hasError
(int msecs = FutureTimeout_Infinite) const
¶Brief:
Parameters: |
|
---|---|
Returns: | true if the future has an error. throw in the following case: timeout |
qi::Future<T>::
hasValue
(int msecs = FutureTimeout_Infinite) const
¶Brief:
Parameters: |
|
---|---|
Returns: | true if the future has a value. throw in the following case: timeout |
qi::Future<T>::
error
(int msecs = FutureTimeout_Infinite) const
¶Brief:
Parameters: |
|
---|---|
Returns: | the error throw on timeout throw if the future do not have an actual error. |
qi::Future<T>::
sync
()¶Make the future sync Should not be useful, use wait().
qi::Future<T>::
cancel
()¶cancel() the asynchronous operation if possible Exact effect is controlled by the cancel implementation, but it is expected to set a value or an error to the Future as fast as possible. Note that cancelation may be asynchronous.
qi::Future<T>::
isCancelable
() const
¶Brief:
Returns: | always true |
---|
Deprecatedsince 2.5
Brief: Execute a callback when the future is finished.
Returns: | a future that will receive the value returned by the callback or an error if the callback threw. |
---|
qi::Future<T>::
thenR
(FutureCallbackType type, AF&& func)¶The callback will receive this future as argument and all other arguments passed to this function.
If the first argument bound to this function is a weak_ptr it will be locked. If it is a Trackable, the callback won’t be called after the object’s destruction. If it is an Actor, the call will be stranded.
Deprecatedsince 2.5 use then()
qi::Future<T>::
thenR
(AF&& func)¶Deprecatedsince 2.5 use then()
()
()
Brief: Execute a callback when the future is finished.
Returns: | a future that will receive the value returned by the callback or an error if the callback threw. |
---|
qi::Future<T>::
then
(FutureCallbackType type, AF&& func)¶The callback will receive this future as argument and all other arguments passed to this function.
If the first argument bound to this function is a weak_ptr it will be locked. If it is a Trackable, the callback won’t be called after the object’s destruction. If it is an Actor, the call will be stranded.
qi::Future<T>::
then
(AF&& func)¶Same as then(), but with type defaulted to FutureCallbackType_Auto.
qi::Future<T>::
andThenR
(FutureCallbackType type, AF&& func)¶The callback will receive the value of this future, as opposed to this future itself.
If this future finishes with an error or a cancel, the callback will not be called and the returned future will finish in the same state.
Deprecatedsince 2.5 use andThen()
qi::Future<T>::
andThenR
(AF&& func)¶Deprecatedsince 2.5 use andThen()
qi::Future<T>::
andThen
(FutureCallbackType type, AF&& func)¶The callback will receive the value of this future, as opposed to this future itself.
If this future finishes with an error or a cancel, the callback will not be called and the returned future will finish in the same state.
qi::Future<T>::
andThen
(AF&& func)¶Same as andThen(), but with type defaulted to FutureCallbackType_Auto.
qi::Future<T>::
makeCanceler
()¶This functor will not keep the future alive, which is useful to avoid reference cycles. If the future does not exist anymore, this is a no-op.
qi::Future<T>::
connect
(const AF& fun, FutureCallbackType type = FutureCallbackType_Auto)¶Connect a callback function that will be called once when the Future finishes (that is, switches from running to an other state).
If type is sync, connect may block and call the callback synchronously if the future is already set.
It guaranteed that your callback will be called exactly once (unless the promise is never set or the promise is reset, which is deprecated).
qi::Future<T>::
connect
(FUNCTYPE fun, ARG0 tracked, ..., FutureCallbackType type = FutureCallbackType_Auto)¶Connect a callback with binding and tracking support.
If the first argument is a weak_ptr or a pointer inheriting from qi::Trackable, the callback will not be called if tracked object was destroyed.
qi::Future<T>::
connectWithStrand
(qi::Strand* strand, const boost::function<void(const Future<T>&)>& cb)¶qi::Future<T>::
connectWithStrand
(qi::Strand& strand, const boost::function<void(const Future<T>&)>& cb)¶qi::Future<T>::
_connect
(const boost::function<void()>& s)¶qi::Future<T>::
impl
()¶Promise
(FutureCallbackType async)Promise
(FUNC&& cancelCallback, FutureCallbackType async)Promise
(boost::function<void(qi::Promise<T>)> cancelCallback, FutureCallbackType async)Promise
(const qi::Promise<T>& rhs)~Promise
()setValue
(const ValueType& value)setError
(const std::string& msg)setCanceled
()isCancelRequested
() constfuture
() constvalue
()trigger
()setOnCancel
(boost::function<void(qi::Promise<T>&)> cancelCallback)operator=
(const Promise<T>& rhs)A Promise is used to create and satisfy a Future.
qi::Promise<T>::
Promise
(FutureCallbackType async = FutureCallbackType_Auto)¶Brief:
Parameters: |
|
---|
Create a standard promise.
qi::Promise<T>::
Promise
(FUNC&& cancelCallback, FutureCallbackType async = FutureCallbackType_Auto)¶Create a canceleable promise. If Future<T>::cancel is invoked, onCancel() will be called. It is expected to call setValue(), setError() or setCanceled() as quickly as possible, but can do so in an asynchronous way.
qi::Promise<T>::
Promise
(boost::function<void(qi::Promise<T>)> cancelCallback, FutureCallbackType async = FutureCallbackType_Auto)¶qi::Promise<T>::
Promise
(const qi::Promise<T>& rhs)¶qi::Promise<T>::
~Promise
()¶qi::Promise<T>::
setValue
(const ValueType& value)¶notify all future that a value has been set. throw if state != running If T is void value must be 0
qi::Promise<T>::
setError
(const std::string& msg)¶set the error, and notify all futures throw if state != running
qi::Promise<T>::
setCanceled
()¶set the cancel state, and notify all futures throw if state != running
qi::Promise<T>::
isCancelRequested
() const
¶return true if cancel has been called on the promise (even if the cancel callback did not run yet).
qi::Promise<T>::
future
() const
¶Get a future linked to this promise. Can be called multiple times.
qi::Promise<T>::
value
()¶Gives access to the underlying value for in-place modification. trigger() must be called after the value is written to trigger the promise.
qi::Promise<T>::
trigger
()¶Trigger the promise with the current value.
qi::Promise<T>::
setOnCancel
(boost::function<void(qi::Promise<T>&)> cancelCallback)¶Set a cancel callback. If the cancel is requested, calls this callback immediately.
qi::Promise<T>::
operator=
(const Promise<T>& rhs)¶FutureSync
()FutureSync
(const Future<T>& b)FutureSync
(const FutureSync<T>& b)FutureSync
(const ValueType& v)operator=
(const FutureSync<T>& b)operator=
(const Future<T>& b)~FutureSync
()operator Future<T>
()operator<
(const FutureSync<T>& b) constuniqueId
() constvalue
(int msecs) constValueTypeCast&
() constwait
(int msecs) constwait
(qi::Duration duration) constwaitFor
(qi::Duration duration) constwait
(qi::SteadyClock::time_point timepoint) constwaitUntil
(qi::SteadyClock::time_point timepoint) constisValid
() constisRunning
() constisFinished
() constisCanceled
() consthasError
(int msecs) consthasValue
(int msecs) consterror
(int msecs) constcancel
()isCancelable
() constconnect
(const Connection& s)_connect
(const boost::function<void()>& s)connect
(FUNCTYPE fun, ARG0 tracked, ...)async
()This class allow throwing on error and being synchronous when the future is not handled by the client.
This class should only be used as return type. If you want to store it, use qi::Future.
qi::FutureSync<T>::
FutureSync
()¶qi::FutureSync<T>::
FutureSync
(const Future<T>& b)¶qi::FutureSync<T>::
FutureSync
(const FutureSync<T>& b)¶qi::FutureSync<T>::
FutureSync
(const ValueType& v)¶qi::FutureSync<T>::
operator=
(const FutureSync<T>& b)¶qi::FutureSync<T>::
operator=
(const Future<T>& b)¶qi::FutureSync<T>::
~FutureSync
()¶will block until the future returns if the future is kept synchronous
qi::FutureSync<T>::
operator
Future<T>()¶qi::FutureSync<T>::
operator<
(const FutureSync<T>& b) const
¶qi::FutureSync<T>::
uniqueId
() const
¶qi::FutureSync<T>::
value
(int msecs = FutureTimeout_Infinite) const
¶qi::FutureSync<T>::
operator
const typename Future<T>::ValueTypeCast&() const
¶qi::FutureSync<T>::
wait
(int msecs = FutureTimeout_Infinite) const
¶qi::FutureSync<T>::
wait
(qi::Duration duration) const
¶qi::FutureSync<T>::
waitFor
(qi::Duration duration) const
¶qi::FutureSync<T>::
wait
(qi::SteadyClock::time_point timepoint) const
¶qi::FutureSync<T>::
waitUntil
(qi::SteadyClock::time_point timepoint) const
¶qi::FutureSync<T>::
isValid
() const
¶qi::FutureSync<T>::
isRunning
() const
¶qi::FutureSync<T>::
isFinished
() const
¶qi::FutureSync<T>::
isCanceled
() const
¶qi::FutureSync<T>::
hasError
(int msecs = FutureTimeout_Infinite) const
¶qi::FutureSync<T>::
hasValue
(int msecs = FutureTimeout_Infinite) const
¶qi::FutureSync<T>::
error
(int msecs = FutureTimeout_Infinite) const
¶qi::FutureSync<T>::
cancel
()¶qi::FutureSync<T>::
isCancelable
() const
¶qi::FutureSync<T>::
connect
(const Connection& s)¶qi::FutureSync<T>::
_connect
(const boost::function<void()>& s)¶qi::FutureSync<T>::
connect
(FUNCTYPE fun, ARG0 tracked, ...)¶Connect a callback with binding and tracking support.
If the first argument is a weak_ptr or a pointer inheriting from qi::Trackable, the callback will not be called if tracked object was destroyed.
qi::FutureSync<T>::
async
()¶qi::
PromiseNoop
(qi::Promise<T>&)¶Helper function that does nothing on future cancelation
Deprecatedsince 2.5: