A C++0x Version
The aforementioned OO-style helper works well in any mainstream language, but in any given language we can often make it even easier by using local language features and idioms. For example, if we were writing it in C++, we could observe that Message and its derived classes are simply applying the usual "OO way" of rolling your own function objects (or functors), and Execute could as well be spelled operator(), the function call operator. The only reason for the Message base class is to provide a way to hold and later invoke an arbitrary message, whereas in C++0x we already have std::function<> as a handy way to hold and later invoke any suitable callable function or functor.
So let's leverage the convenience of C++ function objects. We'll avoid a lot of the "OO Message hierarchy" boilerplate. Active will be a simpler class. Derived classes will be easier to write. What's not to like?
// Example 2: Active helper, in idiomatic C++(0x)
//
class Active {
public:
typedef function<void()> Message;
private:
Active( const Active& ); // no copying
void operator=( const Active& ); // no copying
bool done; // le flag
message_queue<Message> mq; // le queue
unique_ptr<thread> thd; // le thread
void Run() {
while( !done ) {
Message msg = mq.receive();
msg(); // execute message
} // note: last message sets done to true
}
public:
Active() : done(false) {
thd = unique_ptr<thread>(
new thread( [=]{ this->Run(); } ) );
}
~Active() {
Send( [&]{ done = true; } ); ;
thd->join();
}
void Send( Message m ) {
mq.send( m );
}
};
Next, we can use the lambda functions language feature to make an implementing class like Backgrounder even simpler to write, because we don't even have to write the external "launcher" method and the actual body in different places…we can simply write each method the same way we write it naturally, and send the body of the message as a lambda function:
class Backgrounder {
public:
void Save( string filename ) { a.Send( [=] {
…
} ); }
void Print( Data& data ) { a.Send( [=, &data] {
…
} ); }
private:
PrivateData somePrivateStateAcrossCalls;
Active a;
};
This isn't just a C++ trick, by the way. If you're using C#, which also has generalized delegates and lambda functions, you can do likewise. Here's a sketch of how the simplified Backgrounder code would look in C#:
class Backgrounder : IDisposable {
public Backgrounder() { /*…*/ a = new Active(); }
public Dispose() { a.Dispose(); }
public void Save( String filename ) { a.Send( () => {
…
} ); }
public void Print( Data data ) { a.Send( () => {
…
} ); }
private:
PrivateData somePrivateStateAcrossCalls;
Active a;
};
Summary
Unlike with free threading, which lets us randomly do anything at all, active objects make it easier to express what we mean by automatically organizing the private thread's work around an event-driven message pump, naturally expressing isolated private data as simple member data, and offering strong lifetime guarantees by letting us express thread and task lifetime in terms of object lifetime (and therefore directly leverage the rich support for object lifetime semantics already built into our programming languages). All of this raises the semantic level of our program code, and makes our program easier to write, read, and reason about. Major uses for active objects include the same motivating cases as for any threads: to express long-running services (for example, a physics thread or a GUI thread); to decouple independent work (for example, background save, or pipeline stages); to encapsulate resources (for example, I/O streams or certain shared objects). You may never need or want to write a naked thread again.
Coming Up
So far, we've looked only at two of the basics of active objects, namely their lifetimes and asynchronous method call semantics. Next month, we'll complete the overview by considering important remaining details how to handle a methods' return values and/or out parameters, and other kinds of communication back to the caller. Stay tuned.
References
[1] H. Sutter. "Use Threads Correctly = Isolation + Asynchronous Messages" (Dr. Dobb's Digest, April 2009: http://www.drdobbs.com/high-performance-computing/215900465).
[2] R. Lavender and D. Schmidt. "Active Object: An Object Behavioral Pattern for Concurrent Programming" (update of paper published in Pattern Languages of Program Design 2, Addison-Wesley, 1996: http://www.cs.wustl.edu/~schmidt/PDF/Act-Obj.pdf).
[3] The ADAPTIVE Communication Environment (ACE): http://www.cs.wustl.edu/~schmidt/ACE.html.
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.


