C++11 Futures

Feb 25, 2014

Concurrency is one of the most significant challenges facing software
development today. As the gains in processor performance diminish year over
year, additional cores have become the norm. For some years now, multicore
processors have become the norm.

Taking advantage of multiple cores has usually required writing multithreaded
code, which can be complex to design and debug. One of my favourite new
features in the C++11 standard library is the future module. This provides
an extra layer of abstraction over threads, providing a simple mechanism
for asynchronous (ie. concurrent) processing.

What is a ‘future’?

A std::future is an object that represents the future return value of a
function; it is the result of a computation which you need but do not yet have.
A std::future object also represents the current processing state of this
computation; whether or not it has completed, for example.

An asynchronous task (which is generally created on its own thread) makes a
promise that it will process a result at some time in the future and
eventually return this result to the caller.

When are futures useful?

If your application needs to perform a non-trivial computation which could take
quite some time to complete, it is frequently preferrable to perform this
computation asynchronously; that is, in another thread, so the calling or main
function can continue processing, perform other tasks, remain responsive to the
user, and so on.

Futures can also be very useful when there are multiple computations to perform,
and it is not known which will complete first. They can all be initiated at the
same time, and the results picked up as each finishes.

How do I perform an async call?

Imagine we have a boring function which will take an undetermined but long time
to complete:

Rather than calling this function directly and waiting for its result, we can
invoke it asynchronously:

std::future<unsigned>ans=std::async(boring);

What is returned immediately is a future object or token (templated over the
return type of the function we are calling), which allows us to query the status
of the computation, and (once complete) retrieve the result of the boring()
function.

Processing in the calling thread (in this case, main) continues, as the
boring function is spun off into its own thread (an implementation detail) to
be scheduled independently. In this way, we can continue to perform other
processing while this boring work is being done in the background.

To retrieve the answer, we simply call get() on the future object when we
need to access the result:

unsignedresult=ans.get();

This will block until the result of the future is ready, and then return
the value from boring().

To avoid blocking on the result, you can use the wait_for() or wait_until()
methods to check on the status of the future.

How do I monitor the future’s status?

While the calling process is performing other work, it might be useful to check
if the asynchronous processing has completed yet. We can either wait for
a certain time to elapse (wait_for()) or wait until a clock time is reached
(wait_until()). This fragment shows how you can wait 5ms for a result,
retrieving it if available, and continuing if not: