A shared future is a lovely thing to contemplate. A shared_future
, on the other hand, is a slippery beast.
Promises and Futures are great ways of transferring ownership of objects between threads. A common use case is a task queue that allows you to submit tasks and wait on the returned future to get the results.
// submitTask creates a promise and returns the corrosponding future auto future = taskQueue.submitTask( [](){ return someLongRunningOperation(); }); auto result = future.get();
But there are two types of futures - future
and shared_future
. What is the difference and which one should you use?
Both provide access to the (confusingly named) "shared state" that conceptually consists of a flag to say whether the result is available, the result, or possibly an exception. In the case of future
the shared state can only be accessed once - calling get()
provides access but effectively resets the shared state. shared_future
allows the state to be accessed many times, even from different threads - useful if multiple threads need to wait on a result.
A consequence of this design is that future
s cannot be copied, only moved. This can be annoying if you find the need to pass futures around or store them in containers. It is tempting (and I have seen code that does this) to just use shared_future
s, which do not have this limitation.
But although shared_future
acts like a drop-in replacement for future
with the same interface, there is a subtle pitfall.
future::get()
and shared_future::get()
actually do different things.
future::get()
effectively move
s the result back to your code. shared_future::get()
only provides you with a const reference for you to copy.
If performance is a concern (and why else would you be using threads?) then the cost of the copy for large results can be prohibitive. This subtle issue is not obvious when eyeballing the code since the two type of futures appear to behave identicallyIf you really want to have the convenience of shared_future
, consider wrapping large objects in easy-to-copy shared_ptrs
.
For this reason I have added std::shared_future
to my list of C++ features that raise my hackles during code reviews. Unless multiple threads really need to wait on a result, a non-shared future
is probably what you want.