Channels ▼
RSS

.NET

Prefer Using Futures or Callbacks to Communicate Asynchronous Results


Getting Multiple or Interim Results

All of the aforementioned options deal well with return values and output parameters. Finally, however, what if we want to get multiple notifications before the final results, such as partial computation results, updated status such as progress updates, and so on?

We have two main options:

  • Provide an explicit message queue or channel back to the caller, which can enqueue multiple results.
  • Accept a callback to invoke repeatedly to pass multiple results back to the caller.

Example 4 will again use the callback approach. If the caller is itself an active object and the callback it provides is one of its own (asynchronous) methods, we've really combined the two paths and done both bullets at the same time. (Note: Here we're focusing on the interim progress via the statusCallback; for the return value, we'll again just use a "future" as in Examples 1 and 2.)


// Example 4: Returning partial results/status
class Backgrounder {
public:
  // Print() puts print result into spooler, returns one of:
  //   Error (failed, couldn't process or send to spooler)
  //   Printing (sent to spooler and already actively printing)
  //   Queued (sent to spooler but not yet actively printing)
  future<PrintStatus>
  Print(
    Data& data,
    function<void(PrintInfo)> statusCallback
  ) {
    auto p = make_shared<promise<PrintStatus>>();
    future<PrintStatus> ret = p->get_future();
    a.Send( [=, &data] {
      PrintInfo info;
      while( /* not done formatting the data */ ) {
        info.SetPercentDone( /*…*/ );
        statusCallBack( info );      // interim status
        // … do the printing work for another piece of the data …
      } while( /* not done formatting the data */ );
      p->set_value( /* … */ );        // set final result
      info.SetPercentDone( 100 );
      statusCallBack( info );          // final interim status
    } );
    return ret;
  }

This might be used in the GUI thread example as follows:


class MyGUI {
public:
  // …

  // When the user clicks [Print]
  void OnPrintClick() {
    // …
    // … turn on printing icon, etc. …
    // …
    // pass a continuation to be called to give
    // us the result once it's available
    shared_future<PrintStatus> result;
    result = backgrounder.Print( theData,
      < [=]( PrintInfo pi ) { SendPrintInfo( pi, result ); } );
  }

  void OnPrintInfo(
    PrintInfo pi,
    shared_future<PrintStatus> result
  ) {
    // … update print progress bar to
    //     pi.GetPercentDone(), etc. …
    // if this is the last notification
    // (100% done, or result is ready)
    if( result.is_ready() ) {
      // … turn off printing icon, etc. …
    }
  }

Summary

To express return values and "out" parameters from an asynchronous function, including an active object method, either:

  • Return a "future" to invoke that the caller can "pull" the result from (Example 1) or convert it to a "push" (Examples 2(a) and 2(b), and prefer to use ContinueWith where available); or
  • Accept a callback to invoke to "push" the result to the caller when ready (Example 3).

To return multiple partial results, such as partial computations or even just "percent done" progress information, also use a callback (Example 4).

Whenever you provide callbacks, remember that they are running in the callee's context, so we want to keep them as short and noninvasive as possible. One good practice is to have the callback just fire off asynchronous messages or method calls and return immediately.

On Deck

Besides moving work off to a background thread, what else could we use an active object for? We'll consider an example next time, but for now, here's a question for you to ponder: How might you use an active object to replace a mutex on some shared state? Think about ways you might approach that problem, and we'll consider an example in my next column.

References

[1] H. Sutter. Prefer Using Active Objects Instead of Naked Threads. Dr. Dobb's Digest, June 2010.

[2] H. Sutter. Prefer Futures to Baked-In 'Async APIs'. Dr. Dobb's Digest, January 2010.

[3] Task.ContinueWith Method (Action<Task>); MSDN.


Herb Sutter is a bestselling author and consultant on software development topics, and a software architect at Microsoft. He can be contacted at www.gotw.ca.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video