Channels ▼
RSS

C/C++

Prefer Futures to Baked-In "Async APIs"


Option 2: Decouple "What" From "How"

Abstraction to the rescue:

  • Use a separate general-purpose task launcher to launch the work. You probably have a number of options already available in your environment, such as being able to write pool.run( /*task*/ ) to run a task in a Java or .NET thread pool, or async( /*task*/ ) in C++0x.
  • Use futures to manage the asynchronous results. A "future" is an asynchronous value — think of it as a "ticket redeemable for a value in the future." [2] This abstraction is available in Java as Future<T>, in the upcoming C++0x standard as future<T>, and also as Task<T> in the next release of .NET.

For example, here is a simple synchronous call to CallSomeFunc:


// synchronous call (this will block)
int result = CallSomeFunc(x,y,z);

// … code here doesn't run until call completes and result is ready …

// use result which is already available
DoSomethingWith( result );

Here is a corresponding asynchronous call (a mix of C++0x and C# syntax):


// asynchronous call
future<int> result =
  async( ()=<{ return CallSomeFunc(x,y,z); } );

// … code here runs concurrently with CallSomeFunc …

// use result when it's ready (this might block)
DoSomethingWith( result.value() );

The future allows us to decouple the call (launch) from the receiving of the result (join). This allows us full flexibility in how to launch the work without being invasive in either the API which remains synchronous and unaware, or the task handle which is represented as a simple and robust future. Also, we do not need to remember to call an explicit EndXxx method as the cleanup is encapsulated in the future abstraction (typically, the future object's destructor or disposer method).

Here's how it looks in the context of our original example. Note that there is no change to the original API:


// Example 4: Same original synchronous API.
//
RetType DoSomething(
  InParameters ins,
  OutParameters outs
);
// Sample asynchronous calling code
//
void CallerMethod() {
  // …

  // launch work asynchronously (in any
  // fashion; for yuks let's use a thread pool)
  // note that the types of "result" and
  // "outTheOther" are now futures.
  result = pool.run( ()=>{
    DoSomething( this, that, outTheOther ) } );

  // These could also take a long time
  // but now run concurrently with DoSomething
  OtherWork();
  MoreOtherWork();

  // … now use result.wait() (might block) and outOther…
}

Note: For convenience only, I'm showing the code using C# lambda syntax. If you don't have C++0x or C# lambdas available in your environment, you can still do this: Just replace "()=>" with a separate Runnable object (Java), delegate (C#), or functor (C++). The lambda is just syntactic sugar for writing a runnable or functor.

What if we don't want to wait for the result but just want some final steps to be performed whenever the call completes, as in Example 3? Easy: Just make it part of the async work, no callback required:


// Example 5 (compare with Example 3):
// Alternative calling code that doesn't wait
//
void CallerMethod() {
  // …

 // Launch, passing the input parameters.
  // But don't join, just eventually use the result.
  async( ()=>{
    DoSomething( this, that, outTheOther );
    // do whatever is necessary with result
    // (write to disk, update a GUI text box, …)
  } );

  OtherWork();
  MoreOtherWork();

  // … now return without waiting for DoSomething
}

Summary

How should we supply an async version of an API? Often the best answer is to do nothing at all, because a caller can make any call asynchronous externally using features like "async" or task launching together with futures.

If you are providing a framework or library or any other API interface, prefer to keep asynchronous launching ("how") separate from the task to be done ("what"). This path leads to simpler APIs, simpler and more robust calling code, and great flexibility in where and how to execute the work.

Notes

[1] Calling Synchronous Methods Asynchronously

[2] In the past, people have sometimes used the word "future" mean both the asynchronous work and its result, but this is conflating two separate things. Always think of a future as just an asynchronous value or object


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