Futures and Tasks in C++0x
Thursday, 27 March 2008
I had resigned myself to Thread Pools and Futures being punted to TR2 rather than C++0x, but it seems there is potential for some movement on this issue. At the meeting of WG21 in Kona, Hawaii in October 2007 it was agreed to include asynchronous future values in C++0x, whilst excluding thread pools and task launching.
Detlef Vollman has rekindled the effort, and drafted N2561: An Asynchronous Future Value with myself and
Howard Hinnant, based on a discussion including other members of the Standards Committee. This paper proposes four templates:
unique_future
and shared_future
, which are the asynchronous values themselves, and
packaged_task
and promise
, which provide ways of setting the asynchronous values.
Asynchronous future values
unique_future
is very much like unique_ptr
: it represents exclusive ownership of the value. Ownership
of a (future) value can be moved between unique_future
instances, but no two unique_future
instances can
refer to the same asynchronous value. Once the value is ready for retrieval, it is moved out of the internal storage
buffer: this allows for use with move-only types such as std::ifstream
.
Similarly, shared_future
is very much like shared_ptr
: multiple instances can refer to the same
(future) value, and shared_future
instances can be copied around. In order to reduce surprises with this usage (with
one thread moving the value through one instance at the same time as another tries to move it through another instance), the stored
value can only be accessed via const
reference, so must be copied out, or accessed in place.
Storing the future values as the return value from a function
The simplest way to calculate a future value is with a packaged_task<T>
. Much like std::function<T()>
, this
encapsulates a callable object or function, for invoking at a later time. However, whereas std::function
returns the
result directly to the caller, packaged_task
stores the result in a future.
extern int some_function(); std::packaged_task<int> task(some_function); std::unique_future<int> result=task.get_future(); // later on, some thread does task(); // and "result" is now ready
Making a promise
to provide a future value
The other way to store a value to be picked up with a unique_future
or shared_future
is to use a
promise
, and then explicitly set the value by calling the set_value()
member function.
std::promise<int> my_promise; std::unique_future<int> result=my_promise.get_future(); // later on, some thread does my_promise.set_value(42); // and "result" is now ready.
Exceptional returns
Futures also support storing exceptions: when you try and retrieve the value, if there is a stored exception, that exception is
thrown rather than the value being retrieved. With a packaged_task
, an exception gets stored if the wrapped function
throws an exception when it is invoked, and with a promise
, you can explicitly store an exception with the
set_exception()
member function.
Feedback
As the paper says, this is not a finished proposal: it is a basis for further discussion. Let me know if you have any comments.
Posted by Anthony Williams
[/ threading /] permanent link
Tags: threading, futures, asynchronous values, C++0x, wg21
Stumble It! | Submit to Reddit | Submit to DZone
If you liked this post, why not subscribe to the RSS feed or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Design and Content Copyright © 2005-2024 Just Software Solutions Ltd. All rights reserved. | Privacy Policy
No Comments