active objects implementation request for comments

Hi everyone. I've been lurking the mailing list for a couple of months now and this is my first post. I've been toying with an idea now for about 9 years, since college, which I only just realized that C++ and specifically boost gives me the tools that I need to implement it. I am hoping someone on this list would be willing to comment on it, as I hope to submit it for inclusion in boost relatively soon. The general concept is that a calling thread never waits for the return value of a function unless it needs to. In the case where a function is being called, this means that a new thread is created for a function call and an asynchronous return object is returned to the caller. For instance: active_object::active_return<int> ar = active_object::active_function(boost::function0<int>(&doStuff)); a boost::thread was just created which executes doStuff() and stores the return value. The created thread is cleaned up at some later time automatically (or during application shutdown). The function template, active_function return immediately. The user can then wait for doStuff to be completed when he is concerned about it. ar.wait_for_return(); or int i = ar.value(); This makes creating parallel code almost trivial, which was the main goal of the project, to make it easy to utilize newer multi-core processors. Similarly an active_object exists which creates a message thread for an object and serializes all calls to the object: The syntax for using an active_object is a little sloppy and I am not sure I am 100% pleased with it: active_object::active_object<TestClass> ao(new TestClass()); active_object::active_return<int> ar = ao << boost::function1<int, TestClass *>(&TestClass::getInt); int v = ar.value(); It was only after setting out to implement the project did I realize that this concept had been published a few years back under the name "Active Object" (http://en.wikipedia.org/wiki/Active_Object) and there are a couple of similar implementations floating around. Project webpage: http://source.emptycrate.com/projects/activeobjects/ Thanks -Jason Turner -- http://emptycrate.com Games, Programming, Travel & other stuff

AMDG Jason Turner <lefticus <at> gmail.com> writes:
<snip>
Similarly an active_object exists which creates a message thread for an object and serializes all calls to the object:
The syntax for using an active_object is a little sloppy and I am not sure I am 100% pleased with it:
active_object::active_object<TestClass> ao(new TestClass());
active_object::active_return<int> ar = ao << boost::function1<int, TestClass *>(&TestClass::getInt); int v = ar.value();
<snip>
You should not store a pointer you should store a value. If users need a pointer then they can specify it explicitly. active_object::active_object<TestClass> ao; The << operator is not appropriate. A function is better ao.execute(boost::function1<int,TestClass *>(&TestClass::getInt)); You could use operator() but that might still be confusing. ao(boost::function1<int,TestClass *>(&TestClass::getInt)); Ideally you want a0->getInt(); But this is not possible. Another possibility is (ao->*&TestClass::getInt)(); In Christ, Steven Watanabe

On 3/6/07, Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Jason Turner <lefticus <at> gmail.com> writes:
<snip>
You should not store a pointer you should store a value. If users need a pointer then they can specify it explicitly.
active_object::active_object<TestClass> ao;
I agree, in principal, and it was my original intention. However, a design goal was to make sure that any existing class could work with active_object and your above example does not allow for a specific constructor to be called. I guess, however, now that I think about it, if the user needs to call the not-default constructor he can store a pointer.
The << operator is not appropriate. A function is better
ao.execute(boost::function1<int,TestClass *>(&TestClass::getInt));
You could use operator() but that might still be confusing.
ao(boost::function1<int,TestClass *>(&TestClass::getInt));
Ideally you want
a0->getInt();
But this is not possible. Another possibility is
(ao->*&TestClass::getInt)();
I also considered something along the lines of: ao->(&TestClass::getInt); What is your thought on that?
In Christ, Steven Watanabe
-Jason

AMDG Jason Turner <lefticus <at> gmail.com> writes:
<snip>
I agree, in principal, and it was my original intention. However, a design goal was to make sure that any existing class could work with active_object and your above example does not allow for a specific constructor to be called. I guess, however, now that I think about it, if the user needs to call the not-default constructor he can store a pointer.
You can either have N template constructors or use in_place_factory
<snip> I also considered something along the lines of:
ao->(&TestClass::getInt);
What is your thought on that?
Illegal in C++. In Christ, Steven Watanabe

On 3/6/07, Steven Watanabe <steven@providere-consulting.com> wrote:
AMDG
Jason Turner <lefticus <at> gmail.com> writes:
<snip>
I agree, in principal, and it was my original intention. However, a design goal was to make sure that any existing class could work with active_object and your above example does not allow for a specific constructor to be called. I guess, however, now that I think about it, if the user needs to call the not-default constructor he can store a pointer.
You can either have N template constructors or use in_place_factory
<snip> I also considered something along the lines of:
ao->(&TestClass::getInt);
What is your thought on that?
Illegal in C++.
Learn something new every day, I thought the -> operator could take parameters.
In Christ, Steven Watanabe
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- http://emptycrate.com Games, Programming, Travel & other stuff

AMDG Jason Turner <lefticus <at> gmail.com> writes:
Learn something new every day, I thought the -> operator could take parameters.
operator-> can be overloaded, but it behaves differently from all other operators. struct A { void f(); }; struct B { A* operator->() const { return(p); } A* p; }; A a; C c = { &a }; c->f(); //calls a.f(); I can't think of any way to make it do what you want. In Christ, Steven Watanabe

operator-> can be overloaded, but it behaves differently from all other operators.
struct A { void f(); }; struct B { A* operator->() const { return(p); } A* p; };
A a; C c = { &a }; c->f(); //calls a.f();
I can't think of any way to make it do what you want.
Right, I was thinking that something like: operator->(boost::function1<ReturnType, A* a>) { } would be a viable option. I know now that it wouldn't be.
In Christ, Steven Watanabe
-Jason

Jason Turner wrote: There has been some discussions about the future concept on this list and there is an implementation of futures available in the boost sandbox vault here: http://tinyurl.com/2bxjj5. What is the difference between this and your proposal? Regards Hartmut
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Jason Turner Sent: Tuesday, March 06, 2007 3:54 PM To: boost@lists.boost.org Subject: [boost] active objects implementation request for comments
Hi everyone. I've been lurking the mailing list for a couple of months now and this is my first post.
I've been toying with an idea now for about 9 years, since college, which I only just realized that C++ and specifically boost gives me the tools that I need to implement it.
I am hoping someone on this list would be willing to comment on it, as I hope to submit it for inclusion in boost relatively soon.
The general concept is that a calling thread never waits for the return value of a function unless it needs to. In the case where a function is being called, this means that a new thread is created for a function call and an asynchronous return object is returned to the caller. For instance:
active_object::active_return<int> ar = active_object::active_function(boost::function0<int>(&doStuff));
a boost::thread was just created which executes doStuff() and stores the return value. The created thread is cleaned up at some later time automatically (or during application shutdown).
The function template, active_function return immediately. The user can then wait for doStuff to be completed when he is concerned about it.
ar.wait_for_return();
or
int i = ar.value();
This makes creating parallel code almost trivial, which was the main goal of the project, to make it easy to utilize newer multi-core processors.
Similarly an active_object exists which creates a message thread for an object and serializes all calls to the object:
The syntax for using an active_object is a little sloppy and I am not sure I am 100% pleased with it:
active_object::active_object<TestClass> ao(new TestClass());
active_object::active_return<int> ar = ao << boost::function1<int, TestClass *>(&TestClass::getInt); int v = ar.value();
It was only after setting out to implement the project did I realize that this concept had been published a few years back under the name "Active Object" (http://en.wikipedia.org/wiki/Active_Object) and there are a couple of similar implementations floating around.
Project webpage: http://source.emptycrate.com/projects/activeobjects/
Thanks -Jason Turner
-- http://emptycrate.com Games, Programming, Travel & other stuff _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 3/6/07, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote:
Jason Turner wrote:
There has been some discussions about the future concept on this list and there is an implementation of futures available in the boost sandbox vault here: http://tinyurl.com/2bxjj5. What is the difference between this and your proposal?
As far as I can tell, the existing futures implementation does not support the active object (to provide an existing class with a message queue) concept, but it could have been used as the basis for my implementation. I was not aware of the futures project.
Regards Hartmut
-Jason

Jason Turner wrote:
<snip>
IIUC I think there is a similar project being worked on that started as a SoC project last year. See: https://www.boost-consulting.com:8443/svn/main/boost/soc/2006/concurrency - Michael Marcin

On 3/6/07, Michael Marcin <mmarcin@method-solutions.com> wrote:
Jason Turner wrote:
<snip>
IIUC I think there is a similar project being worked on that started as a SoC project last year. See: https://www.boost-consulting.com:8443/svn/main/boost/soc/2006/concurrency
This project looks further along (and more complete) than my own, does anyone know what the status of it is? Is it under active development or being considered for inclusion? -Jason

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Tuesday 06 March 2007 16:54 pm, Jason Turner wrote:
It was only after setting out to implement the project did I realize that this concept had been published a few years back under the name "Active Object" (http://en.wikipedia.org/wiki/Active_Object) and there are a couple of similar implementations floating around.
I've written a little active object framework too. In fact, it was what I was working on which led to me getting quite sidetracked on thread-safe signals. But now that I'm wrapping that up, I should be able to release my code soon. It works, I just haven't released it because I haven't written any documentation yet. I basically just combined ideas from the active object paper by Lavender, et. al., the ACE implementation, and boost, and added some syntactic sugar. I didn't try to provide a full active object class like you did. I provide active functions, futures, method requests, schedulers, and it is up to the user to combine a set of active functions with a scheduler and a servant object to produce their own full active object. - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFF7hKV5vihyNWuA4URAhn6AKDqFSs0VFjFjprqyfXvNlNWSiFl8wCgo057 m/ryB+S/SMGYH67to0+X5Wo= =jnSm -----END PGP SIGNATURE-----

On 3/6/07, Frank Mori Hess <frank.hess@nist.gov> wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Tuesday 06 March 2007 16:54 pm, Jason Turner wrote:
It was only after setting out to implement the project did I realize that this concept had been published a few years back under the name "Active Object" (http://en.wikipedia.org/wiki/Active_Object) and there are a couple of similar implementations floating around.
I've written a little active object framework too. In fact, it was what I was working on which led to me getting quite sidetracked on thread-safe signals. But now that I'm wrapping that up, I should be able to release my code soon. It works, I just haven't released it because I haven't written any documentation yet. I basically just combined ideas from the active object paper by Lavender, et. al., the ACE implementation, and boost, and added some syntactic sugar. I didn't try to provide a full active object class like you did. I provide active functions, futures, method requests, schedulers, and it is up to the user to combine a set of active functions with a scheduler and a servant object to produce their own full active object.
I've implemented a few application specific Active Objects before both with and without Boost. But now that Boost.Asio + Boost.Threads are both available in the Boost CVS, the following could very well be a pattern implementation (untested): template <const Threads=1> class active { boost::asio::io_service _scheduler; boost::asio::io_service::work _work; boost::thread_group _threads; public: active() : _scheduler(), _work(_scheduler), _threads() { for (size_t i=0; i < Threads; ++i) _threads.create_thread( boost::bind(&boost::asio::io_service::run, &_scheduler) ); }; protected: ~active() { _scheduler.interrupt(); _threads.join_all(); }; template <typename T> inline future<T> schedule(boost::function0<T> function) { future<T> result_; _scheduler.post(boost::bind(result_, function)); return result_; }; template <typename T> inline future<T> sync_schedule(boost::function0<T> function) { future<T> result_; _scheduler.post(boost::asio::strand(boost::bind(result_, function))); return result_; }; }; To use an implementation like the one above, the idea is that the class/type that you're making an active object should inherit from the above implementation: struct active_writer : active<> { void write(std::string const & str) { sync_schedule(boost::bind(&active_writer::write_pimpl, this, str)); }; private: void write_pimpl(std::string str) { std::cout << str << std::endl; }; }; typedef active_writer stdout_log; // in client code stdout_log logger; logger.write("The quick brown fox jumps over the lazy dog."); // exits immediately // ------------- This implementation's benefit is that the Active Object pattern implementation would be easier to apply to user generated types meant to be active objects. The implementation also requires a future<T> implementation, which wraps a call to the function and whose function return is either discarded in case T is void or stored otherwise. HTH -- Dean Michael C. Berris http://cplusplus-soup.blogspot.com/ mikhailberis AT gmail DOT com +63 928 7291459

On 3/6/07, Frank Mori Hess <frank.hess@nist.gov> wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Tuesday 06 March 2007 16:54 pm, Jason Turner wrote:
It was only after setting out to implement the project did I realize that this concept had been published a few years back under the name "Active Object" (http://en.wikipedia.org/wiki/Active_Object) and there are a couple of similar implementations floating around.
I've written a little active object framework too. In fact, it was what I was working on which led to me getting quite sidetracked on thread-safe signals. But now that I'm wrapping that up, I should be able to release my code soon. It works, I just haven't released it because I haven't written any documentation yet. I basically just combined ideas from the active object paper by Lavender, et. al., the ACE implementation, and boost, and added some syntactic sugar. I didn't try to provide a full active object class like you did. I provide active functions, futures, method requests, schedulers, and it is up to the user to combine a set of active functions with a scheduler and a servant object to produce their own full active object.
Personally, I am less interested in the algorithmic side and more interested in the non-intrusive active_object<> style wrapper, with asynchronous return types. Either way, it seems this is an idea whose time has come and I would love to see some implementation make its way into boost. If your implementation is further along than my own and more generic, I would be interested in providing help if you need it. The next most obvious place for these concepts to go would be into the realm of multiprocess and distributed computing. A project I was working on at my last company would have benefited greatly by taking the concepts of futures and the python reflection library. As it was, adding new distributed methods and parsing the results, waiting for return values, etc ended up being probably 1/3 of the code. -Jason
Frank

On Wednesday 07 March 2007 14:08 pm, Jason Turner wrote:
Personally, I am less interested in the algorithmic side and more interested in the non-intrusive active_object<> style wrapper, with asynchronous return types. Either way, it seems this is an idea whose time has come and I would love to see some implementation make its way into boost.
If your implementation is further along than my own and more generic, I would be interested in providing help if you need it.
I'll whip up some basic doxygen documentation so the library interface is more intelligible. I'll try to get the code and documentation online somewhere before this weekend, and you can see if it interests you. I arrived at active objects from thinking about doing some kind of dataflow programming in C++. The highest level class in my code is an active function class, which both returns a future and takes futures as arguments. That way, the main thread can setup the flow of data by passing futures between active objects, and then leave them to their work. For example, you might have a batch of objects you want to pass though a pipeline of processing operations. You can do things like assign a Future<T> to a Future<U> if T is implicitly converible to U, without blocking. You can also extract elements from future containers and such, like getting a Future<int> from a Future<std::vector<int> > without blocking. I'm not familiar with the boost::asio library, but I suspect there is stuff in there I could (should) have made use of. -- Frank

The highest level class in my code is an active function class, which both returns a future and takes futures as arguments. That way, the main thread can setup the flow of data by passing futures between active objects, and then leave them to their work. For example, you might have a batch of objects you want to pass though a pipeline of processing operations.
Because of this, I gave my active_return<> class the forbidden implicit cast operator, that way I saved a lot of duplicating what boost::bind was already doing. Example: active_return<int> ar1 = active_function(&getSomeInt); active_return<int> ar2 = active_function(boost::bind(&doSomethingWithAnInt, ar1)); boost::bind stores an active_return<int> in the second line, but does not attempt to use it as an int until the bound function is called. This results in a thread being spawned for getSomeInt and a second thread spawned for doSomethingWithAnInt which waits on the first result. I'm sure someone will take issue with this implementation detail (which is called deplorable in c++ coding standards #40), but it sure does make for clean use of the library.
You can do things like assign a Future<T> to a Future<U> if T is implicitly converible to U, without blocking. You can also extract elements from future containers and such, like getting a Future<int> from a Future<std::vector<int> > without blocking.
Those are great ideas, I had not thought of that.
I'm not familiar with the boost::asio library, but I suspect there is stuff in there I could (should) have made use of.
I am also not familiar with asio and there has been a lot of talk about it here lately.
-- Frank
Jason

On Wednesday 07 March 2007 15:51 pm, Frank Mori Hess wrote:
I'll whip up some basic doxygen documentation so the library interface is more intelligible. I'll try to get the code and documentation online somewhere before this weekend, and you can see if it interests you.
I've got some basic documentation for my active object library done, and the code available from cvs now. See http://www.comedi.org/projects/libpoet/index.html for more information. -- Frank

On Fri, 09 Mar 2007 20:59:02 -0500, Frank Mori Hess wrote:
This is interesting. I've been working in a similar problem domain (dynamic multi-threaded loading and processing with complex pipelines and a lot of io). One problem with the heavy use of futures among asynchronous functions is that when the function waits on a future, it ties up the whole thread - and there may be a limited number. In my opinion, this is one of the more difficult problems in doing this type of scheduled multi-threaded programming in C++. In libpoet's case (and I've only just started looking at it), you might be able to mitigate this somewhat if you check any future<T> arguments for an active_function invocation within a default guard. ie, the default guard for libpoet checks that all future<T> arguments are ready before running the active_function. In general, what is REALLY needed is a form of continuation. Ideally, when future<T>::get() blocks, control of the thread is yielded back to the scheduler, which would continue the function once the future<T> is ready. I noticed that the (very interesting) Intel threading library mentioned earlier has a (very awkward) Continuation concept. I don't think there is really any good way to do this though...perhaps a C++ coroutine implementation would do, but they still scare me. Braddock Gaskill Dockside Vision Inc

On Monday 12 March 2007 06:42 pm, Braddock Gaskill wrote:
In libpoet's case (and I've only just started looking at it), you might be able to mitigate this somewhat if you check any future<T> arguments for an active_function invocation within a default guard. ie, the default guard for libpoet checks that all future<T> arguments are ready before running the active_function.
Yes, I probably neglected to document it, but the poet::active_function always logically ands the ready state of all it's input futures with any guard function you specify. So by default, the method request is ready to run and can be scheduled when all the inputs are ready. -- Frank

On 3/12/07, Braddock Gaskill <braddock@braddock.com> wrote:
On Fri, 09 Mar 2007 20:59:02 -0500, Frank Mori Hess wrote:
This is interesting. I've been working in a similar problem domain (dynamic multi-threaded loading and processing with complex pipelines and a lot of io).
One problem with the heavy use of futures among asynchronous functions is that when the function waits on a future, it ties up the whole thread - and there may be a limited number. In my opinion, this is one of the more difficult problems in doing this type of scheduled multi-threaded programming in C++.
In libpoet's case (and I've only just started looking at it), you might be able to mitigate this somewhat if you check any future<T> arguments for an active_function invocation within a default guard. ie, the default guard for libpoet checks that all future<T> arguments are ready before running the active_function.
In general, what is REALLY needed is a form of continuation. Ideally, when future<T>::get() blocks, control of the thread is yielded back to the scheduler, which would continue the function once the future<T> is ready. I noticed that the (very interesting) Intel threading library mentioned earlier has a (very awkward) Continuation concept.
I don't think there is really any good way to do this though...perhaps a C++ coroutine implementation would do, but they still scare me.
Take a look at my coroutine library, developed during the last SoC: http://www.crystalclearsoftware.com/soc/coroutine/index.html The reference documentation is still missing, but I hope to have it finished very soon now (TM) and submit it for review. And yes, it has futures. Even if the current implementation can only be used to wait for asynchronous asio calls, supporting asynchronous procedures in other threads should be fairly easy. gpd

Looks well done, taking into account just about everything I was concerned about (and more) and making use of the existing future<>. The only thing I would do differently, I think, is add an active_object<> wrapper similar to what is in my library. Basically, I can see a use to providing any generic class with a message queue. Thanks for the docs, let me know if there are any areas which you could see using some help. -Jason On 3/9/07, Frank Mori Hess <frank.hess@nist.gov> wrote:
On Wednesday 07 March 2007 15:51 pm, Frank Mori Hess wrote:
I'll whip up some basic doxygen documentation so the library interface is more intelligible. I'll try to get the code and documentation online somewhere before this weekend, and you can see if it interests you.
I've got some basic documentation for my active object library done, and the code available from cvs now. See
http://www.comedi.org/projects/libpoet/index.html
for more information.
-- Frank
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- http://emptycrate.com Games, Programming, Travel & other stuff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Tuesday 13 March 2007 10:52 am, Jason Turner wrote:
Thanks for the docs, let me know if there are any areas which you could see using some help.
The docs could use some help. In particular, an intro/tutorial type of page. Or just a little example program that shows how a full active object can be built would definitely help. The active object could contain a few public active_function objects corresponding to the "servant" object's public methods, and a private shared_ptr<scheduler> (used by all the active_functions), and a private shared_ptr<servant> to hold the servant object. You might want to wait a few days though, as I'm currently in the process of making a few changes to the API. I've switched to using the slot class from thread_safe_signals for tracking, instead of boost::function + shared_ptr<void>. I'm going to split a reference-counted "promise" class out of the future class as suggested recently on this list, which is responsible for setting the values that futures see. I'm also adding support for forwarding exceptions from an active_function's underlying function to the returned future based on Peter Dimov's exception_ptr. - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFF9vgc5vihyNWuA4URAv13AKCDeiUzYfQu97UOHb9MaZL2dFuZtwCgoWQ3 VwbCVwVzAtCpNRq19Tb9EAM= =KJpH -----END PGP SIGNATURE-----
participants (9)
-
Braddock Gaskill
-
Dean Michael Berris
-
Frank Mori Hess
-
Frank Mori Hess
-
Giovanni Piero Deretta
-
Hartmut Kaiser
-
Jason Turner
-
Michael Marcin
-
Steven Watanabe