Home | Libraries | People | FAQ | More |
Copyright © 2008 Anthony Williams
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Table of Contents
state
enumunique_future
class templateswap()
get()
wait()
timed_wait()
timed_wait()
is_ready()
has_value()
has_exception()
get_state()
shared_future
class templatepromise
class templatepackaged_task
class templatewait_for_any()
wait_for_all()
The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or on a single thread in response to external stimuli, or on-demand.
This is done through the provision of four class templates: jss::unique_future
and jss::shared_future
which are used to retrieve the asynchronous results, and jss::promise
and jss::packaged_task
which are used to generate the asynchronous results.
An instance of jss::unique_future
holds the one and only reference to a result. Ownership can be transferred
between instances using the move constructor or move-assignment operator, but
at most one instance holds a reference to a given asynchronous result. When
the result is ready, it is returned from jss::unique_future<R>::get()
by rvalue-reference to allow the result to be moved or copied as appropriate
for the type.
On the other hand, many instances of jss::shared_future
may reference the same result. Instances can be freely copied and assigned,
and jss::shared_future<R>::get()
returns a const
reference so that
multiple calls to jss::shared_future<R>::get()
are safe. You can move an instance of jss::unique_future
into an instance of jss::shared_future
,
thus transferring ownership of the associated asynchronous result, but not
vice-versa.
You can wait for futures either individually or with one of the jss::wait_for_any()
and jss::wait_for_all()
functions.
You can set the value in a future with either a jss::promise
or a jss::packaged_task
.
A jss::packaged_task
is a callable object that wraps a function or callable object. When the packaged
task is invoked, it invokes the contained function in turn, and populates a
future with the return value. This is an answer to the perennial question:
"how do I return a value from a thread?": package the function you
wish to run as a jss::packaged_task
and pass the packaged task to the thread constructor. The future retrieved
from the packaged task can then be used to obtain the return value. If the
function throws an exception, that is stored in the future in place of the
return value.
int calculate_the_answer_to_life_the_universe_and_everything() { return 42; } jss::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything); jss::unique_future<int> fi=pt.get_future(); boost::thread task(boost::move(pt)); // launch task on a thread fi.wait(); // wait for it to finish assert(fi.is_ready()); assert(fi.has_value()); assert(!fi.has_exception()); assert(fi.get_state()==jss::future_state::ready); assert(fi.get()==42);
A jss::promise
is a bit more low level: it just provides explicit functions to store a value
or an exception in the associated future. A promise can therefore be used where
the value may come from more than one possible source, or where a single operation
may produce multiple values.
jss::promise<int> pi; jss::unique_future<int> fi; fi=pi.get_future(); pi.set_value(42); assert(fi.is_ready()); assert(fi.has_value()); assert(!fi.has_exception()); assert(fi.get_state()==jss::future_state::ready); assert(fi.get()==42);
Both jss::promise
and jss::packaged_task
support wait callbacks that are invoked when a thread
blocks in a call to wait()
or timed_wait()
on a future that is waiting for the result from the jss::promise
or jss::packaged_task
,
in the thread that is doing the waiting. These can be set using the set_wait_callback()
member function on the jss::promise
or jss::packaged_task
in question.
This allows lazy futures where the result is not actually
computed until it is needed by some thread. In the example below, the call
to f.get()
invokes
the callback invoke_lazy_task
,
which runs the task to set the value. If you remove the call to f.get()
, the task is not ever run.
int calculate_the_answer_to_life_the_universe_and_everything() { return 42; } void invoke_lazy_task(jss::packaged_task<int>& task) { try { task(); } catch(jss::task_already_started&) {} } int main() { jss::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything); task.set_wait_callback(invoke_lazy_task); jss::unique_future<int> f(task.get_future()); assert(f.get()==42); }
namespace future_state { enum state {uninitialized, waiting, ready}; }
template <typename R> class unique_future { unique_future(unique_future & rhs);// = delete; unique_future& operator=(unique_future& rhs);// = delete; public: typedef future_state::state state; unique_future(); ~unique_future(); // move support unique_future(unique_future && other); unique_future& operator=(unique_future && other); void swap(unique_future& other); // retrieving the value R&& get(); // functions to check state state get_state() const; bool is_ready() const; bool has_exception() const; bool has_value() const; // waiting for the result to be ready void wait() const; template<typename Duration> bool timed_wait(Duration const& rel_time) const; bool timed_wait_until(boost::system_time const& abs_time) const; };
unique_future();
Constructs an uninitialized future.
this->is_ready
returns false
. this->get_state()
returns jss::future_state::uninitialized
.
Nothing.
unique_future(unique_future && other);
Constructs a new future, and transfers ownership of the asynchronous
result associated with other
to *this
.
this->get_state()
returns the value of other->get_state()
prior to the call. other->get_state()
returns jss::future_state::uninitialized
. If other
was associated with an asynchronous
result, that result is now associated with *this
. other
is not associated with any asynchronous result.
Nothing.
If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.
unique_future& operator=(unique_future && other);
Transfers ownership of the asynchronous result associated with other
to *this
.
this->get_state()
returns the value of other->get_state()
prior to the call. other->get_state()
returns jss::future_state::uninitialized
. If other
was associated with an asynchronous
result, that result is now associated with *this
. other
is not associated with any asynchronous result. If *this
was associated with an asynchronous
result prior to the call, that result no longer has an associated
jss::unique_future
instance.
Nothing.
If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.
void swap(unique_future & other);
Swaps ownership of the asynchronous results associated with other
and *this
.
this->get_state()
returns the value of other->get_state()
prior to the call. other->get_state()
returns the value of this->get_state()
prior to the call. If other
was associated with an asynchronous
result, that result is now associated with *this
, otherwise *this
has no associated result. If *this
was associated with an asynchronous result, that result is now associated
with other
, otherwise
other
has no associated
result.
Nothing.
R&& get(); R& unique_future<R&>::get(); void unique_future<void>::get();
If *this
is associated with an asynchronous result, waits until the result is
ready as-if by a call to jss::unique_future<R>::wait()
,
and retrieves the result (whether that is a value or an exception).
If the result type R
is a reference, returns the stored reference. If R
is void
, there is no return
value. Otherwise, returns an rvalue-reference to the value stored in
the asynchronous result.
this->is_ready()
returns true
. this->get_state()
returns jss::future_state::ready
.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception stored in
the asynchronous result in place of a value.
get()
is an interruption point.
void wait();
If *this
is associated with an asynchronous result, waits until the result is
ready. If the result is not ready on entry, and the result has a wait
callback set, that callback is invoked prior to waiting.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception thrown by
the wait callback if such a callback is called.
this->is_ready()
returns true
. this->get_state()
returns jss::future_state::ready
.
wait()
is an interruption point.
template<typename Duration> bool timed_wait(Duration const& wait_duration);
If *this
is associated with an asynchronous result, waits until the result is
ready, or the time specified by wait_duration
has elapsed. If the result is not ready on entry, and the result has
a wait callback set, that callback is invoked
prior to waiting.
true
if *this
is associated with an asynchronous result, and that result is ready
before the specified time has elapsed, false
otherwise.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception thrown by
the wait callback if such a callback is called.
If this call returned true
,
then this->is_ready()
returns true
and this->get_state()
returns jss::future_state::ready
.
timed_wait()
is an interruption point. Duration
must be a type that meets the Boost.DateTime time duration requirements.
bool timed_wait(boost::system_time const& wait_timeout);
If *this
is associated with an asynchronous result, waits until the result is
ready, or the time point specified by wait_timeout
has passed. If the result is not ready on entry, and the result has
a wait callback set, that callback is invoked
prior to waiting.
true
if *this
is associated with an asynchronous result, and that result is ready
before the specified time has passed, false
otherwise.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception thrown by
the wait callback if such a callback is called.
If this call returned true
,
then this->is_ready()
returns true
and this->get_state()
returns jss::future_state::ready
.
timed_wait()
is an interruption point.
bool is_ready();
Checks to see if the asynchronous result associated with *this
is set.
true
if *this
is associated with an asynchronous result, and that result is ready
for retrieval, false
otherwise.
Nothing.
bool has_value();
Checks to see if the asynchronous result associated with *this
is set with a value rather than an exception.
true
if *this
is associated with an asynchronous result, that result is ready for
retrieval, and the result is a stored value, false
otherwise.
Nothing.
bool has_exception();
Checks to see if the asynchronous result associated with *this
is set with an exception rather than a value.
true
if *this
is associated with an asynchronous result, that result is ready for
retrieval, and the result is a stored exception, false
otherwise.
Nothing.
future_state::state get_state();
Determine the state of the asynchronous result associated with *this
,
if any.
jss::future_state::uninitialized
if *this
is not associated with an asynchronous result. jss::future_state::ready
if the asynchronous
result associated with *this
is ready for retrieval, jss::future_state::waiting
otherwise.
Nothing.
template <typename R> class shared_future { public: typedef future_state::state state; shared_future(); ~shared_future(); // copy support shared_future(shared_future const& other); shared_future& operator=(shared_future const& other); // move support shared_future(shared_future && other); shared_future(unique_future<R> && other); shared_future& operator=(shared_future && other); shared_future& operator=(unique_future<R> && other); void swap(shared_future& other); // retrieving the value R get(); // functions to check state, and wait for ready state get_state() const; bool is_ready() const; bool has_exception() const; bool has_value() const; // waiting for the result to be ready void wait() const; template<typename Duration> bool timed_wait(Duration const& rel_time) const; bool timed_wait_until(boost::system_time const& abs_time) const; };
shared_future();
Constructs an uninitialized future.
this->is_ready
returns false
. this->get_state()
returns jss::future_state::uninitialized
.
Nothing.
const R& get();
If *this
is associated with an asynchronous result, waits until the result is
ready as-if by a call to jss::shared_future<R>::wait()
,
and returns a const
reference
to the result.
If the result type R
is a reference, returns the stored reference. If R
is void
, there is no return
value. Otherwise, returns a const
reference to the value stored in the asynchronous result.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted.
get()
is an interruption point.
void wait();
If *this
is associated with an asynchronous result, waits until the result is
ready. If the result is not ready on entry, and the result has a wait
callback set, that callback is invoked prior to waiting.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception thrown by
the wait callback if such a callback is called.
this->is_ready()
returns true
. this->get_state()
returns jss::future_state::ready
.
wait()
is an interruption point.
template<typename Duration> bool timed_wait(Duration const& wait_duration);
If *this
is associated with an asynchronous result, waits until the result is
ready, or the time specified by wait_duration
has elapsed. If the result is not ready on entry, and the result has
a wait callback set, that callback is invoked
prior to waiting.
true
if *this
is associated with an asynchronous result, and that result is ready
before the specified time has elapsed, false
otherwise.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception thrown by
the wait callback if such a callback is called.
If this call returned true
,
then this->is_ready()
returns true
and this->get_state()
returns jss::future_state::ready
.
timed_wait()
is an interruption point. Duration
must be a type that meets the Boost.DateTime time duration requirements.
bool timed_wait(boost::system_time const& wait_timeout);
If *this
is associated with an asynchronous result, waits until the result is
ready, or the time point specified by wait_timeout
has passed. If the result is not ready on entry, and the result has
a wait callback set, that callback is invoked
prior to waiting.
true
if *this
is associated with an asynchronous result, and that result is ready
before the specified time has passed, false
otherwise.
jss::future_uninitialized
if *this
is not associated with an asynchronous result. boost::thread_interrupted
if the result associated with *this
is not ready at the point of the
call, and the current thread is interrupted. Any exception thrown by
the wait callback if such a callback is called.
If this call returned true
,
then this->is_ready()
returns true
and this->get_state()
returns jss::future_state::ready
.
timed_wait()
is an interruption point.
bool is_ready();
Checks to see if the asynchronous result associated with *this
is set.
true
if *this
is associated with an asynchronous result, and that result is ready
for retrieval, false
otherwise.
Nothing.
bool has_value();
Checks to see if the asynchronous result associated with *this
is set with a value rather than an exception.
true
if *this
is associated with an asynchronous result, that result is ready for
retrieval, and the result is a stored value, false
otherwise.
Nothing.
bool has_exception();
Checks to see if the asynchronous result associated with *this
is set with an exception rather than a value.
true
if *this
is associated with an asynchronous result, that result is ready for
retrieval, and the result is a stored exception, false
otherwise.
Nothing.
future_state::state get_state();
Determine the state of the asynchronous result associated with *this
,
if any.
jss::future_state::uninitialized
if *this
is not associated with an asynchronous result. jss::future_state::ready
if the asynchronous
result associated with *this
is ready for retrieval, jss::future_state::waiting
otherwise.
Nothing.
template <typename R> class promise { promise(promise & rhs);// = delete; promise & operator=(promise & rhs);// = delete; public: // template <class Allocator> explicit promise(Allocator a); promise(); ~promise(); // Move support promise(promise && rhs); promise & operator=(promise&& rhs); void swap(promise& other); // Result retrieval unique_future<R> get_future(); // Set the value void set_value(R& r); void set_value(R&& r); void set_exception(boost::exception_ptr e); template<typename F> void set_wait_callback(F f); };
promise();
Constructs a new jss::promise
with no associated
result.
Nothing.
promise(promise && other);
Constructs a new jss::promise
, and transfers ownership
of the result associated with other
to *this
,
leaving other
with
no associated result.
Nothing.
If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.
promise& operator=(promise && other);
Transfers ownership of the result associated with other
to *this
,
leaving other
with
no associated result. If there was already a result associated with
*this
,
and that result was not ready, sets any futures
associated with that result to ready with a jss::broken_promise
exception as the result.
Nothing.
If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.
~promise();
Destroys *this
.
If there was a result associated with *this
, and that result is not ready,
sets any futures associated with that task to ready
with a jss::broken_promise
exception as the result.
Nothing.
unique_future<R> get_future();
If *this
was not associated with a result, allocate storage for a new asynchronous
result and associate it with *this
. Returns a jss::unique_future
associated with
the result associated with *this
.
jss::future_already_retrieved
if the future
associated with the task has already been retrieved. std::bad_alloc
if any memory necessary
could not be allocated.
void set_value(R&& r); void set_value(const R& r); void promise<R&>::set_value(R& r); void promise<void>::set_value();
If *this
was not associated with a result, allocate storage for a new asynchronous
result and associate it with *this
. Store the value r
in the asynchronous result associated
with *this
.
Any threads blocked waiting for the asynchronous result are woken.
All futures waiting on the asynchronous result are ready
and jss::unique_future<R>::has_value()
or jss::shared_future<R>::has_value()
for those futures shall return true
.
jss::promise_already_satisfied
if the
result associated with *this
is already ready.
std::bad_alloc
if the memory required
for storage of the result cannot be allocated. Any exception thrown
by the copy or move-constructor of R
.
void set_exception(boost::exception_ptr e);
If *this
was not associated with a result, allocate storage for a new asynchronous
result and associate it with *this
. Store the exception e
in the asynchronous result associated
with *this
.
Any threads blocked waiting for the asynchronous result are woken.
All futures waiting on the asynchronous result are ready
and jss::unique_future<R>::has_exception()
or jss::shared_future<R>::has_exception()
for those futures shall return true
.
jss::promise_already_satisfied
if the
result associated with *this
is already ready.
std::bad_alloc
if the memory required
for storage of the result cannot be allocated.
template<typename F> void set_wait_callback(F f);
The expression f(t)
where t
is a lvalue
of type jss::packaged_task
shall be well-formed.
Invoking a copy of f
shall have the same effect as invoking f
Store a copy of f
with
the asynchronous result associated with *this
as a wait callback.
This will replace any existing wait callback store alongside that result.
If a thread subsequently calls one of the wait functions on a jss::unique_future
or jss::shared_future
associated with this result, and the result is not ready,
f(*this)
shall be invoked.
std::bad_alloc
if memory cannot be allocated
for the required storage.
template<typename R> class packaged_task { packaged_task(packaged_task&);// = delete; packaged_task& operator=(packaged_task&);// = delete; public: // construction and destruction template <class F> explicit packaged_task(F const& f); explicit packaged_task(R(*f)()); template <class F> explicit packaged_task(F&& f); // template <class F, class Allocator> // explicit packaged_task(F const& f, Allocator a); // template <class F, class Allocator> // explicit packaged_task(F&& f, Allocator a); ~packaged_task() {} // move support packaged_task(packaged_task&& other); packaged_task& operator=(packaged_task&& other); void swap(packaged_task& other); // result retrieval unique_future<R> get_future(); // execution void operator()(); template<typename F> void set_wait_callback(F f); };
template<typename F> packaged_task(F const &f); packaged_task(R(*f)()); template<typename F> packaged_task(F&&f);
f()
is a valid expression with a return type convertible to R
. Invoking a copy of f
shall behave the same as invoking
f
.
Constructs a new jss::packaged_task
with a copy
of f
stored as the
associated task.
Any exceptions thrown by the copy (or move) constructor of f
. std::bad_alloc
if memory for the internal data structures could not be allocated.
packaged_task(packaged_task && other);
Constructs a new jss::packaged_task
, and transfers
ownership of the task associated with other
to *this
,
leaving other
with
no associated task.
Nothing.
If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.
packaged_task& operator=(packaged_task && other);
Transfers ownership of the task associated with other
to *this
,
leaving other
with
no associated task. If there was already a task associated with *this
,
and that task has not been invoked, sets any futures associated with
that task to ready with a jss::broken_promise
exception as the result.
Nothing.
If the compiler does not support rvalue-references, this is implemented using the boost.thread move emulation.
~packaged_task();
Destroys *this
.
If there was a task associated with *this
, and that task has not been invoked,
sets any futures associated with that task to ready
with a jss::broken_promise
exception as the result.
Nothing.
unique_future<R> get_future();
Returns a jss::unique_future
associated with
the result of the task associated with *this
.
jss::task_moved
if ownership of the task
associated with *this
has been moved to another instance of jss::packaged_task
. jss::future_already_retrieved
if the future
associated with the task has already been retrieved.
void operator()();
Invoke the task associated with *this
and store the result in the corresponding
future. If the task returns normally, the return value is stored as
the asynchronous result, otherwise the exception thrown is stored.
Any threads blocked waiting for the asynchronous result associated
with this task are woken.
All futures waiting on the asynchronous result are ready
jss::task_moved
if ownership of the task
associated with *this
has been moved to another instance of jss::packaged_task
. jss::task_already_started
if the task
has already been invoked.
template<typename F> void set_wait_callback(F f);
The expression f(t)
where t
is a lvalue
of type jss::packaged_task
shall be well-formed.
Invoking a copy of f
shall have the same effect as invoking f
Store a copy of f
with
the task associated with *this
as a wait callback.
This will replace any existing wait callback store alongside that task.
If a thread subsequently calls one of the wait functions on a jss::unique_future
or jss::shared_future
associated with this task, and the result of the task is not ready,
f(*this)
shall be invoked.
jss::task_moved
if ownership of the task
associated with *this
has been moved to another instance of jss::packaged_task
.
template<typename Iterator> Iterator wait_for_any(Iterator begin,Iterator end); template<typename F1,typename F2> unsigned wait_for_any(F1& f1,F2& f2); template<typename F1,typename F2,typename F3> unsigned wait_for_any(F1& f1,F2& f2,F3& f3); template<typename F1,typename F2,typename F3,typename F4> unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4); template<typename F1,typename F2,typename F3,typename F4,typename F5> unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5);
The types Fn
shall be
specializations of jss::unique_future
or jss::shared_future
, and Iterator
shall be a forward iterator
with a value_type
which
is a specialization of jss::unique_future
or jss::shared_future
.
Waits until at least one of the specified futures is ready.
The range-based overload returns an Iterator
identifying the first future in the range that was detected as ready.
The remaining overloads return the zero-based index of the first future
that was detected as ready (first parameter =>
0, second parameter => 1, etc.).
boost::thread_interrupted
if the current thread
is interrupted. Any exception thrown by the wait callback
associated with any of the futures being waited for. std::bad_alloc
if memory could not be allocated for the internal wait structures.
wait_for_any()
is an interruption point.
template<typename Iterator> void wait_for_all(Iterator begin,Iterator end); template<typename F1,typename F2> void wait_for_all(F1& f1,F2& f2); template<typename F1,typename F2,typename F3> void wait_for_all(F1& f1,F2& f2,F3& f3); template<typename F1,typename F2,typename F3,typename F4> void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4); template<typename F1,typename F2,typename F3,typename F4,typename F5> void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5);
The types Fn
shall be
specializations of jss::unique_future
or jss::shared_future
, and Iterator
shall be a forward iterator
with a value_type
which
is a specialization of jss::unique_future
or jss::shared_future
.
Waits until all of the specified futures are ready.
Any exceptions thrown by a call to wait()
on the specified futures.
wait_for_all()
is an interruption point.
Last revised: May 30, 2008 at 09:30:07 GMT |