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’?
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.
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:
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
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:
This will block until the result of the
future is ready, and then return
the value from
To avoid blocking on the result, you can use the
methods to check on the status of the
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:
A more complete example shows monitoring the status of multiple
displaying the result as each finishes is available in the
C++11 async sample code