Prefer Using Futures or Callbacks to Communicate Asynchronous Results
Handling asynchronous communication back to the caller
Option 1: Return a Future (Caller Naturally "Pulls")
First, let's deal with just the return value and output parameters, which should be somehow communicated back to the caller at the end of the asynchronous method. To keep the code simple, we'll focus on the primary return value; output parameters are conceptually just additional return values and can be handled the same way.
For an asynchronous method call, we want to express its return value as an asynchronous result. The default tool to use for an asynchronous value is a "future" (see [2]). To keep the initial example simple, let's say that Save just wants to return whether it succeeded or failed, by returning a bool:
// Example 1: Return value, using a future
class Backgrounder {
public:
future<bool> Save( string filename ) {
// Make a future (to be waited for by the caller)
// connected to a promise (to be filled in by the callee)
auto p = make_shared<promise<bool>>();
future<bool> ret = p->get_future();
a.Send( [=] {
// … do the saving work …
p->set_value( didItSucceed() ? true : false );
} );
return ret;
}
(C++0x-specific note: Why are we holding the promise by reference-counted smart pointer? Because promise is a move-only type and C++ lambdas do not yet support move-capture, only capture-by-value and capture-by-reference. One simple solution is to hold the promise by shared_ptr, and copy that.)
Now the caller can wait for the "future":
future<bool> result = backgrounder.Save( filename ); … … this code can run concurrently with Save() … Use( result.get() ); // block if necessary until result is available
This works, and returning a "future" is generally a useful mechanism.
However, notice that waiting for a "future" is inherently a "pull" operation; that is, the caller has to ask for the result when it's needed. For callers who want to find out if the result is ready without blocking if it isn't, "future" types typically provide a status method like result.is_ready() for the caller to check without blocking, which he can do in a loop and then sleep in between calls that's still a form of polling loop, but at least it's better than burning CPU cycles with outright busy-waiting.
So, although the caller isn't forced to busy-wait, the onus is still on him to act to "pull" the value. What can we do if instead the caller wants a "push" notification sent to him proactively when the result is available? Let's consider two ways, which we'll call Options 2 and 3.








