Active objects offer an important abstraction above raw threads. In a previous article, we saw how active objects let us hide the private thread, deterministically organize the thread's work, isolate its private data, express asynchronous messages as ordinary method calls, and express thread/task lifetimes as object lifetimes so that we can manage both using the same normal language features. [1]

What we didn't cover, however, was how to handle methods' return values and/or "out" parameters, and other kinds of communication back to the caller. This time, we'll answer the following questions:

How should we express return values and out parameters from an asynchronous function, including an active object method?

How should we give back multiple partial results, such as partial computations or even just "percent done" progress information?

Which mechanisms are suited to callers that want to "pull" results, as opposed to having the callee "push" the results back proactively? And how can "pull" be converted to "push" when we need it?

Let's dig in.

Getting Results: Return Values and "Out" Parameters

First, let's recall the active object example we introduced last time.

We have a GUI thread that must stay responsive, and to keep it ready to handle new messages we have to move "save this document," "print this document," and any other significant work off the responsive thread to run asynchronously somewhere else. One way to do that is to have a background worker thread that handles the saving and print rendering work. We feed the work to the background thread by sending it asynchronous messages that contain the work to be performed; the messages are queued up if the worker thread is already busy, and then executed sequentially on the background worker thread.

The following code expresses the background worker using a Backgrounder class that follows the active object pattern. The code we'll show uses C++0x syntax, but can be translated directly into other popular threading environments such as those provided by Java, .NET, and Pthreads (see [1] for a discussion of the pattern and translating the code to other environments).

The Active helper member encapsulates a private thread and message queue, and each Backgrounder method call simply captures its parameters and its body (both conveniently automated by using lambda function syntax) and Send that as an asynchronous message that's fired off to be enqueued and later executed on the private thread:

// Baseline example class Backgrounder { public: void Save( string filename ) { a.Send( [=] { // … do the saving work … } ); } void Print( Data& data ) { a.Send( [=, &data] { do { // … do the printing work for another piece of the data … } while( /* not done formatting the data */ ); } ); } private: PrivateData somePrivateStateAcrossCalls; Active a; // encapsulates a private thread, and }; // pumps method calls as messages

The GUI thread instantiates a single Backgrounder object (and therefore a single background worker thread), which might be used from the GUI thread as follows:

class MyGUI { public: // When the user clicks [Save] void OnSaveClick() { // … // … turn on saving icon, etc. … // … backgrounder.Save( filename ); // this fires off an asynchronous message } // and then we return immediately to the caller // … private: Backgrounder backgrounder; };