Future of threads (III)

hi y'all, i have been listening-in to the recent thread thread (intentional); its worth it! threading is a special interest for myself at the moment. i have been working on something different (distributed messaging) and have been forced to consider threading. again and again. it seems to be impossible to address the one (messaging) without also addressing the other (multi-threading). this would come as no real surprise to anyone, but the slightly unnerving thing has been the "distance" between the threading model that seems to fulfil the requirements of my distributed messaging and the model in boost::threads. this is not intended to question the validity of that model; quite the opposite. i have wondered if my model is invalid and considered the task of "porting" the messaging code to the boost model (if not the implementation) calling it the "boost model" seems a little unfair as i think i can say it is in the spirit of other implementations such as rogue wave's. recent work has taken me on a different path. i have been cornered into applying my messaging+threading model within a significant body of complex production code. millions of lines of code and dozens of threads. the interesting thing (for me :-) has been how effectively the new threading model has integrated with the existing model(s). this did make me feel better about the track i had taken. so, is there room for 2? very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects. the distinguishing attribute being that threads only run code that is "part of themselves" rather than code being submitted from "outside". execution of the code is initiated by sending of a message (within my vocabulary that is actually a signal). the message can contain arbitrary data. is this different enough? is there enough value there? cheers, scott

On Thursday 12 February 2004 05:28 pm, scott wrote:
so, is there room for 2?
Sure. One "obvious" question is whether your threading library would need to be completely separate, or whether it should be implemented as a layer on top of something like the existing Threads library. I personally don't care much for the "standard" way of writing multithreading programs, because it quite error-prone. Other methods, like the one you propose and others such as the Join calculus, are less error-prone and often more expressive. But, operating systems and VMs provide "standard" threading models, so something like Boost.Threads can be a good implementation base for higher-level multithreading, distributed, and parallel programming styles.
very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects. the distinguishing attribute being that threads only run code that is "part of themselves" rather than code being submitted from "outside". execution of the code is initiated by sending of a message (within my vocabulary that is actually a signal). the message can contain arbitrary data.
This reminds me of the actor model of distributed computation. If you are familiar with actors, could you briefly compare/contrast your approach against them? Doug

[mailto:boost-bounces@lists.boost.org]On Behalf Of Douglas Gregor Sent: Friday, February 13, 2004 11:56 AM
On Thursday 12 February 2004 05:28 pm, scott wrote:
so, is there room for 2?
Sure. One "obvious" question is whether your threading library would need to be completely separate, or whether it should be implemented as a layer on top of something like the existing Threads library.
hmmm, yes. had wandered down this road. you could say that i stubbed my toe on a small rock with "join" written on it. the whole issue of error handling around join was very relevant. exceptions in the alternate model are caught (or not ;-) within the object that "is" the thread. there is not the same need to transfer error information between threads out of some sense of righteousness (you gave me this code to run, now you eat this exception). but that is somewhat convenient. i dont have any real case for not building on top of boost::threads. i would wonder about losing touch with the available threading primitives. its hard enough making it work without having to work through an intermediary. but hiding the specifics of threads is a major benefit of boost::threads so i will (head down) look into this. the result wouldnt be an "alternate" model though :-)
very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects. the distinguishing attribute being that threads only run code that is "part of themselves" rather than code being submitted from "outside". execution of the code is initiated by sending of a message (within my vocabulary that is actually a signal). the message can contain arbitrary data.
This reminds me of the actor model of distributed computation. If you are familiar with actors, could you briefly compare/contrast your approach against them?
i know of uml's actor but not sure if that's the same thing. and my knowledge of uml is so lame i suspect i shouldnt attempt any analogies. was there some specific aspect of alt-threads that needed elaboration (yeah, like everything :-) or were you suggesting a new direction for me to check out? cheers, scott

On Fri, 13 Feb 2004 14:15:19 +1300, scott wrote
very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects. the distinguishing attribute being that threads only run code that is "part of themselves" rather than code being submitted from "outside". execution of the code is initiated by sending of a message (within my vocabulary that is actually a signal). the message can contain arbitrary data.
This reminds me of the actor model of distributed computation. If you are familiar with actors, could you briefly compare/contrast your approach against them?
i know of uml's actor but not sure if that's the same thing. and my knowledge of uml is so lame i suspect i shouldnt attempt any analogies.
I believe you'all are talking about 'Active Objects'. Doug Schmidt, primary author of ACE, has written extensively on this subject. Take a look at this paper: http://citeseer.nj.nec.com/lavender96active.html ACE has direct support for the paradigm. It's been a couple years since I looked at it, but as I recall using a bunch of template magic object methods are morphed into stubs that queue messages for the object thus disconnecting the requesting thread from the execution of the method. Jeff

On Thursday 12 February 2004 09:58 pm, Jeff Garland wrote:
I believe you'all are talking about 'Active Objects'. Doug Schmidt, primary author of ACE, has written extensively on this subject. Take a look at this paper:
Interesting... I'm not familiar with this methodology. <heaves the paper onto the "To Read" stack> Doug

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org]On Behalf Of Jeff Garland Sent: Friday, February 13, 2004 3:58 PM To: Boost mailing list Subject: RE: [boost] Future of threads (III)
This reminds me of the actor model of distributed computation. If you are familiar with actors, could you briefly compare/contrast your approach against them?
i know of uml's actor but not sure if that's the same thing. and my knowledge of uml is so lame i suspect i shouldnt attempt any analogies.
I believe you'all are talking about 'Active Objects'. Doug Schmidt, primary author of ACE, has written extensively on this subject. Take a look at this paper:
Thanks. AOs have a significant number of similarities with the model that I have been working with; e.g. scheduler, servant. There are also some differences. Some of these can be considered implementation specifics while others are differences in design goal or underlying paradigm. Method Request is the object sent by a client, queued in a scheduler and performed within a servant. The AO pattern defines a request+results model, i.e. an asynchronous modeling of the traditional synchronous call (arguments = requests, results = return value). The pattern does allow for deviation from this model with one-way methods. For several reasons I have found this "unsuitable". Firstly the adoption of "method" as part of the vocabulary is unfortunate (at least, according to me :-) It brings with it "synchronous baggage". A strange symptom that I have encountered is a difficulty in separating client code from server code, i.e. clients sometimes include a quantity of inert and redundant server code. Also, the interaction with servants tends to involve more than a single exchange (request+result). A much more flexible model can be built on a "send" primitive (i.e. from SDL) which achieves something very similar to the internal workings of AO "methods". This breaks away from the Q+A model, allowing for "one-way", "two-way" or "any-old-way". The relative "looseness" of send vs method can be too much for some. It could be argued that a one-way method allows for all of this. As long as that facillity is buried within the larger method-based document then I think it is too effectively mis-represented. The "method-based" thinking also results in C++ classes with methods that translate to each of the messages that might be sent. In my book this is tantamount to the servant claiming ownership of the protocol. I'll skip the tedious explanation of that one and just say "i really struggle with that one". There is some notion of "a main application" and servants or schedulers that might be available. I question why there is a distinction. The transfer of a Method Request to a servant is so similar to the transfer of results back; to not use the same technique seems almost tragic. I have applied the alternate model into existing frameworks and been pleasantly surprised, i.e. it was easy to present "theApp" (MFC/AFX) as a scheduler. A difficulty inherent in "breaking away" (from the method model) are the objects that are exchanged (previously "Method Requests"). In the new model these objects have some very interesting (i.e. painful) requirements. I'll skip another long explanation for a time when someone actually wants it :-) Thanks again for the reference. It is material I definitely needed to cover. I think it was very close but did have different goals. Cheers, Scott

Jeff Garland <jeff <at> crystalclearsoftware.com> writes:
I believe you'all are talking about 'Active Objects'. Doug Schmidt, primary author of ACE, has written extensively on this subject. Take a look at this paper:
http://citeseer.nj.nec.com/lavender96active.html
ACE has direct support for the paradigm. It's been a couple years since I looked at it, but as I recall using a bunch of template magic object methods are morphed into stubs that queue messages for the object thus disconnecting the requesting thread from the execution of the method.
This is an interesting idea, using the boundaries of objects as the interaction points between threads. I have no experience with this sort of threading, but your comments led me to sketch out a wrapper which could be used to give 'active object' behaviour to existing classes, which might provide a simple pattern for concurrency in some apps... Anyway: // Code ---------------------------------------------------- #include <iostream> #include <queue> #include <string> #include <boost/any.hpp> #include <boost/bind.hpp> #include <boost/function.hpp> #include <boost/thread.hpp> #include <boost/tuple/tuple.hpp> #include <boost/utility.hpp> // Pinched from the boost::threads example... template <typename T, size_t size = 5> struct bounded_buffer { bounded_buffer(void) : begin(0), end(0), buffered(0), circular_buffer(size) { } void enqueue (T t) { boost::mutex::scoped_lock lock(mutex); while (buffered == circular_buffer.size()) buffer_not_full.wait(lock); circular_buffer[end] = t; end = (end+1) % circular_buffer.size(); ++buffered; buffer_not_empty.notify_one(); } T dequeue(void) { boost::mutex::scoped_lock lock(mutex); while (buffered == 0) buffer_not_empty.wait(lock); T t = circular_buffer[begin]; begin = (begin+1) % circular_buffer.size(); --buffered; buffer_not_full.notify_one(); return t; } private: int begin, end, buffered; std::vector<T> circular_buffer; boost::condition buffer_not_full, buffer_not_empty; boost::mutex mutex; }; // Wrapper class to supply active behaviour to other objects template <typename Base> class Active { typedef boost::function<boost::any (void)> task_type; typedef boost::tuple<task_type, boost::any*, boost::condition*, boost::mutex*> task_descriptor; void thread_function(void) { while (true) { task_descriptor td = tasks.dequeue(); task_type task = td.template get<0>(); boost::any* result = td.template get<1>(); boost::condition* condition = td.template get<2>(); boost::mutex* mutex = td.template get<3>(); if (result == NULL) break; *result = task(); boost::mutex::scoped_lock lock(*mutex); (*condition).notify_all(); } } static boost::any end_function(void) { std::string ("Hideous hack to end thread for Active<Object>"); } bounded_buffer<task_descriptor> tasks; task_descriptor end_task; boost::thread thread; protected: Active(void) : thread(boost::bind(&Active<Base>::thread_function, this)), end_task(end_function, NULL, NULL, NULL) { } ~Active() { tasks.enqueue(end_task); thread.join(); } template <typename result_type> result_type invoke(task_type task, boost::condition& condition, boost::mutex& mutex) { boost::any result; task_descriptor td(task, &result, &condition, &mutex); boost::mutex::scoped_lock lock(mutex); tasks.enqueue(td); while (result.empty()) condition.wait(lock); return boost::any_cast<result_type>(result); } // Only handles non-void functions with one parameter, currently template <typename Signature> class Proxy { typedef typename boost::function_traits<Signature>::result_type result_type; typedef typename boost::function_traits<Signature>::arg1_type arg1_type; typedef result_type (Base::*method_type)(arg1_type); typedef boost::function<result_type (arg1_type)> wrapper_type; typedef boost::function<result_type (task_type, boost::condition&, boost::mutex&)> invocation_type; static boost::any wrap(wrapper_type task, arg1_type arg1) { return task(arg1); } invocation_type invocation; wrapper_type task; public: Proxy(Base* object, method_type method, Active<Base>* active) { task = boost::bind(method, object, _1); invocation = boost::bind(&Active<Base>::invoke<result_type>, active, _1, _2, _3); } result_type operator()(arg1_type arg1) { boost::mutex mutex; boost::condition condition; return invocation(boost::bind(&wrap, task, arg1), condition, mutex); } }; }; // User Code ----------------------------------------------------------- using std::cout; using std::cin; using std::endl; // An example class to test active behaviour struct Object { int method(int i) { cout << "In Object::method" << endl; return (i+1); } float another(float f) { cout << "In Object::another" << endl; return (f*f); } }; // An active version of the Object class struct ActiveObject : private Active<Object> { ActiveObject() : object(), method(&object, &Object::method, this), another(&object, &Object::another, this) { } Object object; public: // Proxy declarations for all methods of the active object Proxy<int (int)> method; Proxy<float (float)> another; }; int main(int, char**) { ActiveObject object; // Is there any way to yield a printable thread id with boost::thread, // to demonstrate that the control passes to another thread? cout << "Invoking methods from main thread" << endl; int i = object.method(5); cout << "Result of method: " << i << endl; float f = object.another(3.1415927f); cout << "Result of another: " << f << endl; cout << "\nPress <Enter> to continue..." << endl; cin.get(); return 0; } // Done ------------------------------------------------ It may be of some utility, especially if it can be reworked to allow for interface inheritance from the wrapped object. If nothing else, it shows how lots of boost libraries can be combined in a short space of lines... I'm sure it can stand a lot of refinement, but I can't be bothered working on it any more! Matt

On Mon, 16 Feb 2004 22:51:18 +0000 (UTC), Matthew Vogt wrote
Jeff Garland <jeff <at> crystalclearsoftware.com> writes:
ACE has direct support for the paradigm. It's been a couple years since I looked at it, but as I recall using a bunch of template magic object methods are morphed into stubs that queue messages for the object thus disconnecting the requesting thread from the execution of the method.
This is an interesting idea, using the boundaries of objects as the interaction points between threads. I have no experience with this sort of threading, but your comments led me to sketch
Interestingly, neither do I -- other than being aware of the ideas and having looked at how it might be applied. I never found an application where this made more sense than thread pools or some other more pedestrian threading model...
out a wrapper which could be used to give 'active object' behaviour to existing classes, which might provide a simple pattern for concurrency in some apps...
Anyway:
...lengthy code example snipped...
It may be of some utility, especially if it can be reworked to allow for interface inheritance from the wrapped object. If nothing else, it shows how lots of boost libraries can be combined in a short space of lines...
All I can say is wow and very impressive! I believe you have managed to leverage the power of several boost libraries very nicely. Anyway, I think the example is a bit contrived in that having the main thread block for a response, but still very cool. One of the interesting points of your example is that a cross-thread queue is needed. Several people have mentioned this as a priority for the thread library and I agree. Every multi-threaded app I've seen needs a cross-thread queue...
I'm sure it can stand a lot of refinement, but I can't be bothered working on it any more!
Too bad, seems like you could make a nice contribution :-( Jeff

Jeff Garland <jeff <at> crystalclearsoftware.com> writes:
This is an interesting idea, using the boundaries of objects as the interaction points between threads. I have no experience with this sort of threading, but your comments led me to sketch
Interestingly, neither do I -- other than being aware of the ideas and having looked at how it might be applied. I never found an application where this made more sense than thread pools or some other more pedestrian threading model...
Do you know what classes of apps use the active object pattern? The example in the Douglas Schmidt paper doesn't really provide much explanation for why you might want active local objects.
It may be of some utility, especially if it can be reworked to allow for interface inheritance from the wrapped object. If nothing else, it shows how lots of boost libraries can be combined in a short space of lines...
All I can say is wow and very impressive! I believe you have managed to leverage the power of several boost libraries very nicely. Anyway, I think the example is a bit contrived in that having the main thread block for a response, but still very cool.
Thank you. Yes, it is very contrived, and fairly limited. But, since I don't actually know why I might want to even use it myself, I wasn't really concerned with improving the code too much. It is a good feeling, though, to be typing in 'boost::' even more often than 'std::'... :)
One of the interesting points of your example is that a cross-thread queue is needed. Several people have mentioned this as a priority for the thread library and I agree. Every multi-threaded app I've seen needs a cross-thread queue...
Absolutely. I have never seen a multi-threaded app that didn't boil down to thread-safe queue access, although I'll admit that there are many classes of app that I have never seen. FWIW, Raoul Gough mentioned his 'safe_queue' (sp?) in the 'Future of threads (II)' thread, but it didn't seem to be ready for public display.
I'm sure it can stand a lot of refinement, but I can't be bothered working on it any more!
Too bad, seems like you could make a nice contribution
No, the fact is I can't grok how boost::function<> parses it arguments, and a working sketch was good enough for me. Now, if only I knew of a reason why I might want to actually *use* it... Matt

On Tue, 17 Feb 2004 01:51:17 +0000 (UTC) Matthew Vogt <mvogt@juptech.com> wrote:
Do you know what classes of apps use the active object pattern? The example in the Douglas Schmidt paper doesn't really provide much explanation for why you might want active local objects.
I think it makes good sense in what ACE is mainly used for: network based server applications. You can write your code inside an ACE_Task, and then it can be used in a reactor-type single threaded app, or it can be used with multiple threads, and for the most part, you can use the same code.
concerned with improving the code too much. It is a good feeling, though, to be typing in 'boost::' even more often than 'std::'... :)
<grin>
No, the fact is I can't grok how boost::function<> parses it arguments, and a working sketch was good enough for me. Now, if only I knew of a reason why I might want to actually *use* it...
I think it is beneficial for most tasks. However, like most paradigms, you have to slightly skew your point of view to see how it really applies. If you have experience doing multithreaded apps, or network based servers, or "sysv-streams-type" stuff, or message passing protocols, or task-based-components then you may be able to see that you can create an active object, which contains a certain amount of execution knowledge, and then that object can do its work, without knowledge of any specific threading mechanisms. You simply communicate via passing messages (e.g., through a message queue), and the active object itself knows how to interpret and handle the requests. Hmmm. Not very convincing is it ;-> -- Jody Hagins Let not the sands of time get in your lunch.

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org]On Behalf Of Matthew Vogt Sent: Tuesday, February 17, 2004 2:51 PM To: boost@lists.boost.org Subject: [boost] Re: Future of threads (III)
Jeff Garland <jeff <at> crystalclearsoftware.com> writes:
This is an interesting idea, using the boundaries of objects as the interaction points between threads. I have no experience with this sort of threading, but your comments led me to sketch
Interestingly, neither do I -- other than being aware of the ideas and having looked at how it might be applied. I never found an application where this made more sense than thread pools or some other more pedestrian threading model...
Do you know what classes of apps use the active object pattern? The example in the Douglas Schmidt paper doesn't really provide much explanation for why you might want active local objects.
erm not entirely sure of what constitutes an "active object app" but what the hey! here's my best shot. imagine a distributed system that needs a db server. or more accurately the system needs an implementation of a specific data model that supports the operation of the system. an "interface" needs to be available. this interface must be able to cope with requests from multiple threads, it must be asynchronous (does not block clients) as anything else would be create a terminal bottleneck. it would seem quite natural for the "interface" to be an active object, accepting requests from multiple client threads and returning results as they become available. at the very least the "interface" (active object) should be a distinct thread. internally there may be more threads processing the actual db queries (whatever is optimal for the underlying db i/f). imagine there is more than the one data model. or imagine that the distributed system must integrate with an external system. the external system would itself be running according to some operational model. this would seem to require a multiplicity of active objects. while this example might characterize active objects as something relevant to larger developments i think that the pattern can be applied within a single desktop app. i would guess that the internals of ms word would be pretty substantial. and maybe an active object that encapsulates all access to the registry (persistent store) would be a nice way to engineer things. for a last, desparate shot; i have personally been involved in several telephony developments that simply would not have completed without active object thinking. hope this was what you were wondering about...
All I can say is wow and very impressive! I believe you
have managed to
leverage the power of several boost libraries very nicely.
yes. this code has legs! cheers, scott

scott <scottw <at> qbik.com> writes:
imagine a distributed system that needs a db server. or more accurately the system needs an implementation of a specific data model that supports the operation of the system. an "interface" needs to be available. this interface must be able to cope with requests from multiple threads, it must be asynchronous (does not block clients) as anything else would be create a terminal bottleneck.
it would seem quite natural for the "interface" to be an active object, accepting requests from multiple client threads and returning results as they become available. at the very least the "interface" (active object) should be a distinct thread. internally there may be more threads processing the actual db queries (whatever is optimal for the underlying db i/f).
Yeah, this makes sense to me. Jeff's telephony example also seems to fit conceptually; I think the degree to which an Active Object (TM) perspective fits a given task depends on the granularity of the objects, and the apparent atomicity of the object. A representation of a telephone makes a much cleaner active object than a bunch of related resources cobbled together as class MyImportantObject.
yes. this code has legs!
cheers, scott
Well, no, actually - as I discovered when trying to generalise it :) I do have a better version, which I'll post when I'm happy with it. Matt

On Tue, 17 Feb 2004 01:51:17 +0000 (UTC), Matthew Vogt wrote
Do you know what classes of apps use the active object pattern? The example in the Douglas Schmidt paper doesn't really provide much explanation for why you might want active local objects.
Sure, there are lots of cases where I can imagine the active object being a nice abstraction. I believe the key uses are where there is distributed object state and timing/hardware resources that need to be handled. For example, imagine that we are creating a server that manages call processing for telephones. We would have a few active objects here -- device objects to represent the phones and 'call state' objects to represent the connection between the phones. The device objects need to synchronize their access to hardware resources, including periodic polling of device state (off hook, on-hook, etc). So it makes lots of sense for a single thread of execution to manage this hardware device. There is also a need for other objects to change the state of the phone device object by sending it messages or commands (eg: connect to tone, hang up, etc). The 'call state' object is an independent thread of execution as it needs to manage timing issues (eg: after 10 seconds give nasty tone to caller since they only dialed three digits and stopped) as well as interact with the devices involved in the call. The 'call state' object would be created when a phone begins the process of making a call and persist until that call is complete. I've worked on these kinds of systems, but it was mostly before objects had become practical to use.... This is in contrast to something like a 'Market Data Server' which would take a data feed of trading data from a stock exchange, update a database, do some data transformation, and distribute information to clients. In this case there is no hardware state to maintain. And yeah, we might want another thread to put stuff in the database so the server doesn't block waiting for the database but Active Objects just don't really add much here. As for whether active objects are local or distributed across several processes in the example I gave they would typically be distributed, but they wouldn't have to be. The key is that the practical issues of managing the resource accesses and timing make the AO a nice match for the actual problem. Finally, in the POSA2 book Schmidt et. al (http://www.cs.wustl.edu/~schmidt/POSA/) cite an automatic call router and an imaging system application as the example apps. Jeff

On Thursday 12 February 2004 08:15 pm, scott wrote:
but that is somewhat convenient. i dont have any real case for not building on top of boost::threads. i would wonder about losing touch with the available threading primitives. its hard enough making it work without having to work through an intermediary. but hiding the specifics of threads is a major benefit of boost::threads so i will (head down) look into this.
the result wouldnt be an "alternate" model though :-)
From the programmer's perspective, it is an alternative model: you don't need to show them the threads underneath, you just need to show them the high-level interface.
Here's the rub: I'm interested. The problem is that I don't want this library lost because it needs to be implemented for Posix, and Windows, and Mac, and we tend to be rather skeptical about platform-specific libraries :)
This reminds me of the actor model of distributed computation. If you are familiar with actors, could you briefly compare/contrast your approach against them?
i know of uml's actor but not sure if that's the same thing. and my knowledge of uml is so lame i suspect i shouldnt attempt any analogies.
I was not referring to UML actors, but to a model for (distributed) computation.
was there some specific aspect of alt-threads that needed elaboration (yeah, like everything :-) or were you suggesting a new direction for me to check out?
Well, you might be interested in this: http://www.cs.rpi.edu/courses/spring03/dci/actor-semantics.pdf It describes the actor model of computation, which I think you might be interested in. Doug

On Thu, 12 Feb 2004 23:36:59 -0500 Douglas Gregor <gregod@cs.rpi.edu> wrote:
From the programmer's perspective, it is an alternative model: you don't need to show them the threads underneath, you just need to show them the high-level interface.
Check out the doxygen documentation page for ACE_Task (http://www.dre.vanderbilt.edu/Doxygen/Beta/html/ace/a01703.html), which provides the ability to encapsulate the behaviour inside a class (for added benefit the task can run in the main thread, or it can run in a separated thread just as easily), and provides a message queue (appropriately locked for separate threads) for communication. I use it quite a bit, and it is quite flexible...

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org]On Behalf Of Douglas Gregor Sent: Friday, February 13, 2004 5:37 PM To: Boost mailing list Subject: Re: [boost] Future of threads (III)
This reminds me of the actor model of distributed computation. If you are familiar with actors, could you briefly compare/contrast your approach against them?
i know of uml's actor but not sure if that's the same thing. and my knowledge of uml is so lame i suspect i shouldnt attempt any analogies.
I was not referring to UML actors, but to a model for (distributed) computation.
was there some specific aspect of alt-threads that needed elaboration (yeah, like everything :-) or were you suggesting a new direction for me to check out?
Well, you might be interested in this:
http://www.cs.rpi.edu/courses/spring03/dci/actor-semantics.pdf
Erm, wow! A little too much "convex, must and may collapsing in the presence of fairness" for my palate :-) I soldiered on "in the presence of send" (refer to a previous mail) to the point where I could vaguely imagine an MPL implementation of their actor language. But that is where my capabilities hit a flat-spot. I can appreciate the desire to found "actors" in a theory. There is also (probably) a healthy proportion of "experts" around RDBMS's that know little about set theory. I will (rather blindly ;-) assume that one day all "inherited thread-type" systems will be validated using some form of actor algebra. Agree with everything said about platform-independence. Cheers, Scott

scott wrote:
very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects.
This is how I've always dealt with threads. I think you can create the same effect with Boost threads if you really want to however: struct A { boost::thread* t; A() { t = new boost::thread( *this ); } void operator()() { ... } }; The only irritating thing is that Boost threads need to be passed the executing object on construction so you need to allocate it dynamically. I'll admit I do prefer the inheritance model in most cases. Perhaps a new class called thread_base could be added so both methods are available? It would be a pretty simple addition. Sean

Sean Kelly <sean@ffwd.cx> writes:
scott wrote:
very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects.
This is how I've always dealt with threads. I think you can create the same effect with Boost threads if you really want to however:
struct A { boost::thread* t; A() { t = new boost::thread( *this ); } void operator()() { ... } };
The only irritating thing is that Boost threads need to be passed the executing object on construction so you need to allocate it dynamically.
You might be able to get around that using boost::optional. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Sean Kelly wrote:
scott wrote:
very briefly, the boost model treats threads as a resource (fair enough to :-) and submits code fragments for asynchronous execution. in the alternate model, threads come about as a consequence of instantiating final (a la java) objects.
This is how I've always dealt with threads. I think you can create the same effect with Boost threads if you really want to however:
struct A { boost::thread* t; A() { t = new boost::thread( *this ); } void operator()() { ... } };
The only irritating thing is that Boost threads need to be passed the executing object on construction so you need to allocate it dynamically.
I'll admit I do prefer the inheritance model in most cases. Perhaps a new class called thread_base could be added so both methods are available? It would be a pretty simple addition.
Did you have something like this in mind: // untested code class thread_base : noncopyable { public: thread_base() : pThread_( new boost::thread( *this ) ) {} ~thread_base() { pThread_->join(); delete pThread_; } private: virtual void operator()() = 0; friend class boost::thread; boost::thread * pThread_; }; ? If yes, how do you ensure that operator() is not called before the subclass object is fully constructed? Moreover, when destructing the subclass object we have the problem that the subclass portion of the thread object is destructed before we call join() in the base class. So, to make the thread_base safe, we have to do the following: class thread_base : noncopyable { public: ~thread_base() { delete pThread_; } void start() { pThread_ = new boost::thread( *this ); } void join() { pThread_->join(); } private: virtual void operator()() = 0; friend class boost::thread; boost::thread * pThread_; }; And call start() in the subclass constructor and call join() in the subclass destructor, what can be easily forgotten by someone deriving from thread_base. I think this was one of the reasons why the design of boost::thread did not go down this road... Regards, Andreas

On Fri, 13 Feb 2004, Andreas Huber wrote:
Sean Kelly wrote:
Did you have something like this in mind:
No. I was thinking about a class that didn't use the existing boost::thread class at all. Downside is redundant code, but not very much: class thread_base { public: thread_base(); virtual ~thread(); void start(); void join() const; private: virtual void operator()() = 0; #if defined( BOOST_HAS_WINTHREADS ) static unsigned __stdcall thread_func( void* arg ); void* m_thread; unsigned m_id; #elif defined( BOOST_HAS_PTHREADS ) static void* thread_func( void* arg ); pthread_t m_thread; #endif };
And call start() in the subclass constructor and call join() in the subclass destructor, what can be easily forgotten by someone deriving from thread_base. I think this was one of the reasons why the design of boost::thread did not go down this road...
The user could delete the object passed to boost::thread with the existing design and there would be no provision for calling join. If this is enough of a concern, make the thread_base destructor a pure virtual function and document the need to call join. Sean

Sean Kelly wrote: [snip]
The user could delete the object passed to boost::thread with the existing design and there would be no provision for calling join. If this is enough of a concern, make the thread_base destructor a pure virtual function and document the need to call join.
Yes, but the user still has to know/remember that (s)he has to call join() in the derived class destructor and start() in the constructor. I think the boost::thread design is much less error-prone here. Plus, with the boost::thread design it is easy to avoid lifetime issues altogether: // untested code class MyActiveObject { public: void Run() { // ... } }; // ... boost::thread myThread( boost::function< void () >( boost::shared_ptr< MyActiveObject >( new MyActiveObject() ), &MyActiveObject::Run ) ); This will work even if you forget to call join() before destructing the thread object... Regards, Andreas

Andreas Huber wrote:
Yes, but the user still has to know/remember that (s)he has to call join() in the derived class destructor and start() in the constructor. I think the boost::thread design is much less error-prone here.
I don't think it's too much to expect a user to know how to properly use a class, provided proper use is documented, but this is really a matter of opinion. I mentioned the design as one that I favor, and I'll continue to use it whether it becomes a part of Boost or not :) Sean

Sean Kelly wrote:
Andreas Huber wrote:
Yes, but the user still has to know/remember that (s)he has to call join() in the derived class destructor and start() in the constructor. I think the boost::thread design is much less error-prone here.
I don't think it's too much to expect a user to know how to properly use a class, provided proper use is documented, but this is really a matter of opinion. I mentioned the design as one that I favor, and I'll continue to use it whether it becomes a part of Boost or not :)
Which is just fine for me :). Surely, you and others preferring an inheritance-based thread design have very valid reasons to do so. In a real-world project environment non-technical reasons are often more important than technical ones. I just don't think the same is true for boost libraries. Especially if the library in question is bound to become very popular, it's a bad idea to settle for anything less than the simplest, least error-prone and most obvious interface possible... Regards, Andreas

Hello, sorry for slight OT but as for now there is a discussion which is entittled future of threads I wonder why those additions( which were mentioned here http://www.cuj.com/documents/s=8470/cuj0205kempf/ There will be a boost::read_write_mutex, which will allow multiple threads to read from the shared resource at the same time, but will ensure exclusive access to any threads writing to the shared resource. There will also be a boost::thread_barrier, which will make a set of threads wait until all threads have "entered" the barrier. A boost::thread_pool is also planned to allow for short routines to be executed asynchronously without the need to create or destroy a thread each time. ) are stilll not in the main tree? not finished patches ( have some shortcomings )are here http://groups.yahoo.com/group/boost/files/thread_pool.zip http://groups.yahoo.com/group/boost/files/thread_barrier_v2.zip http://groups.yahoo.com/group/boost/files/thread_rw_lock_v2.zip Regards Serge

Sergey Kurdakov wrote:
Hello, sorry for slight OT but as for now there is a discussion which is entittled future of threads
I wonder why those additions( which were mentioned here http://www.cuj.com/documents/s=8470/cuj0205kempf/
There will be a boost::read_write_mutex, which will allow multiple threads to read from the shared resource at the same time, but will ensure exclusive access to any threads writing to the shared resource. There will also be a boost::thread_barrier, which will make a set of threads wait until all threads have "entered" the barrier. A boost::thread_pool is also planned to allow for short routines to be executed asynchronously without the need to create or destroy a thread each time.
) are stilll not in the main tree?
The reason is that William Kempf, the Boost.Thread maintainer and the author of the article you link to above, apparently stopped active development of Boost.Thread. There was previous discussion about this not long ago in this newsgroup.
not finished patches ( have some shortcomings )are here
http://groups.yahoo.com/group/boost/files/thread_pool.zip http://groups.yahoo.com/group/boost/files/thread_barrier_v2.zip http://groups.yahoo.com/group/boost/files/thread_rw_lock_v2.zip
These are old. Newer versions are in the Boost CVS on the thread_dev branch. I hope to move suitably modified versions of these and other changes that William Kemp added to the thread_dev branch in the coming weeks. In fact, see thread "Moving Boost.Thread barrier from thread_dev to HEAD".
Regards Serge
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Sean Kelly wrote:
The user could delete the object passed to boost::thread with the existing design and there would be no provision for calling join.
I think that you are wrong. A boost::thread makes a copy of its function object. The user can't delete it. You can explicitly force a boost::thread to not make a copy by using ref() and then delete the object, of course, if you like.

Peter Dimov wrote:
Sean Kelly wrote:
The user could delete the object passed to boost::thread with the existing design and there would be no provision for calling join.
I think that you are wrong. A boost::thread makes a copy of its function object. The user can't delete it.
I think he meant the object indirectly referenced by boost::function: MyActiveObject pActive = new MyActiveObject(); boost::thread myThread( boost::function< void () >( boost::bind( &MyActiveObject::Run, pActive ) ) ); delete pActive; It's questionable however, whether it's a good idea not to use a smart pointer here... Regards, Andreas

Andreas Huber wrote:
Peter Dimov wrote:
Sean Kelly wrote:
The user could delete the object passed to boost::thread with the existing design and there would be no provision for calling join.
I think that you are wrong. A boost::thread makes a copy of its function object. The user can't delete it.
I think he meant the object indirectly referenced by boost::function:
MyActiveObject pActive = new MyActiveObject(); boost::thread myThread( boost::function< void () >( boost::bind( &MyActiveObject::Run, pActive ) ) ); delete pActive;
Why would anyone want to do that? boost::thread myThread( boost::bind( &MyActiveObject::Run, MyActiveObject() ) ); Or if Run is renamed to operator(): boost::thread myThread( MyActiveObject() );

Peter Dimov wrote:
Andreas Huber wrote:
Peter Dimov wrote:
Sean Kelly wrote:
The user could delete the object passed to boost::thread with the existing design and there would be no provision for calling join.
I think that you are wrong. A boost::thread makes a copy of its function object. The user can't delete it.
Oops, I hadn't realized that.
I think he meant the object indirectly referenced by boost::function:
MyActiveObject pActive = new MyActiveObject(); boost::thread myThread( boost::function< void () >( boost::bind( &MyActiveObject::Run, pActive ) ) ); delete pActive;
Why would anyone want to do that?
What if MyActiveObject has interface methods that need to be externally accessible? Message queue endpoints, for example. Though other program designs might obviate the need for such access methods. Sean

Sean Kelly wrote:
Peter Dimov wrote:
Andreas Huber wrote:
I think he meant the object indirectly referenced by boost::function:
MyActiveObject pActive = new MyActiveObject(); boost::thread myThread( boost::function< void () >( boost::bind( &MyActiveObject::Run, pActive ) ) ); delete pActive;
Why would anyone want to do that?
What if MyActiveObject has interface methods that need to be externally accessible? Message queue endpoints, for example. Though other program designs might obviate the need for such access methods.
Yes, that's how I would answer my own question, too. It would be interesting to see whether high-level components built on top of boost::thread can solve the interthread communication problem in an elegant way. But if we focus on the low-level layer, I think that this may be solved with a thread::target() accessor (similar to the newly added function<>::target()).

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org]On Behalf Of Peter Dimov Sent: Tuesday, February 17, 2004 9:29 AM To: Boost mailing list Subject: Re: [boost] Re: Re: Future of threads (III)
Sean Kelly wrote:
Peter Dimov wrote:
Andreas Huber wrote:
I think he meant the object indirectly referenced by boost::function:
MyActiveObject pActive = new MyActiveObject(); boost::thread myThread( boost::function< void () >( boost::bind( &MyActiveObject::Run, pActive ) ) ); delete pActive;
Why would anyone want to do that?
What if MyActiveObject has interface methods that need to be externally accessible? Message queue endpoints, for example. Though other program designs might obviate the need for such access methods.
Yes, that's how I would answer my own question, too. It would be interesting to see whether high-level components built on top of boost::thread can solve the interthread communication problem in an elegant way. But if we focus on the low-level layer, I think that this may be solved with a thread::target() accessor (similar to the newly added function<>::target()).
Hoping you guys dont mind, but i have summarized some recent messages WRT the original question. Which was "is there room for 2?" DG mentioned boost::threads. And you guys kinda sorted out how to make an object equivalent to a thread (using boost::threads)? This direction looks fine to me (we have platform independence). I am assuming that the code that is presented for execution is some kind of message queue processing and that that processing results in calls to a method or methods in the "thread derived" class? Something like this needs to happen (I think) if there is going to be a class that has the appearance of running as an independent thread. This seems more confusing than it needs to be. So I'll wind it back and try again. I think that the concept of "class that is a thread" is a compelling one. The Active Object pattern is a pretty damn good formalization of what many people would tacitly understand the concept to be. I suspect that a small gap exists between that "tacit understanding" and what we (i.e. you guys) have been working through. My best identification of that gap goes like this... An AO is something that comes into existence, certain events are directed to it and it responds to them. This describes an object that receives "work to do" over time. Work is not submitted (in fact, cannot be) at ctor time. So far we have a thread that can call a method within another class, i.e. become the class. Do you guys have any thoughts on how to "get work into" the class (now that it is truly a running thread)? Cos this is the essence of what an AO is. I think :-) Cheers, Scott

scott wrote:
I am assuming that the code that is presented for execution is some kind of message queue processing and that that processing results in calls to a method or methods in the "thread derived" class? Something like this needs to happen (I think) if there is going to be a class that has the appearance of running as an independent thread.
I agree. The object model has always made more sense to me in this case as the thread and executing object code seem tightly bound. I do sometimes use a "job queue" however, that's sort of a fancy thread pool which uses job objects much like the Boost design. This was really designed for short-term or fire-and-forget tasks however.
I think that the concept of "class that is a thread" is a compelling one. The Active Object pattern is a pretty damn good formalization of what many people would tacitly understand the concept to be.
If a person is creating an object that is going to be executed as a thread, he must do so deliberately. Synchronization points must be considered, etc. To me, the inheritance model more accurately communicates the purpose of such a design than does the Boost model. but it also assumes that the object *is* a thread rather than that it can be used in an asynchronous fashion. I think there are definite applications for both designs.
An AO is something that comes into existence, certain events are directed to it and it responds to them. This describes an object that receives "work to do" over time. Work is not submitted (in fact, cannot be) at ctor time.
Another model that suits this design is a pool of anonymous worker threads, though it's perhaps conceptually a bit less obvious. With that model, you have a bunch of threads that pull tasks of a job queue and process them. State information is stored as part of the message or by some other means. IOCP is a perfect example of this.
Do you guys have any thoughts on how to "get work into" the class (now that it is truly a running thread)? Cos this is the essence of what an AO is. I think :-)
Depends on the application, I suppose :) I wrote a comm. framework a few years ago that makes fairly heavy use of proxy objects and callbacks. Some other applications may be simpler and just expose methods directly on the subclassed thread object. Sean

scott wrote:
Hoping you guys dont mind, but i have summarized some recent messages WRT the original question.
Which was "is there room for 2?"
DG mentioned boost::threads. And you guys kinda sorted out how to make an object equivalent to a thread (using boost::threads)?
Not really, no. An object can never be equivalent to a thread. These are two separate concepts. You can kinda tie the lifetime of a thread with the lifetime of the object and make the one accessible from the other, but that doesn't make them equivalent; they are still separate entities held together by duct tape. And once you reach a certain complexity threshold the "a thread is an object" pattern will limit your options. It is better to keep the object and the thread separate (I'll use Andreas Huber's suggestion for the example): shared_ptr<ActiveObject> px(new ActiveObject(...)); thread exec( bind(&ActiveObject::run, px) ); Now you have access to the object via px, and you have access to the thread via exec. You can throw away both px and exec and the thread will still continue to execute normally since it keeps a reference to *px and won't let it die. Furthermore, this separation allows you to execute an ActiveObject synchronously without a thread, if you like: px->run(); and it also allows you to execute an ActiveObject in a thread pool: my_thread_pool pool(16, 4); pool.queue( bind(&ActiveObject::run, px) ); Note that in these two examples, there is no one-to-one correspondence between the active objects and the threads.

[mailto:boost-bounces@lists.boost.org]On Behalf Of Peter Dimov
DG mentioned boost::threads. And you guys kinda sorted out how to make an object equivalent to a thread (using boost::threads)?
Not really, no. An object can never be equivalent to a thread. These are two separate concepts.
yes. my misuse of the word "equivalent".
You can kinda tie the lifetime of a thread with the lifetime of the object and make the one accessible from the other, but that doesn't make them equivalent; they are still separate entities held together by duct tape. And once you reach a certain complexity threshold the "a thread is an object" pattern will limit your options.
hmmmm. ultimately agree with this; no-one wants to maintain a 300-thread system and no platform wants to run it (presenting a position here rather than being technically accurate :-) that being so the ActiveObject pattern does not prescribe a thread per object. the pattern defines schedulers and servants. there is a (platform) thread per scheduler and any number of servants related to that scheduler. i am guessing that the "active object" referred to in recent messages, best maps to "servant". this model might seem unnecessarily complex or a knee-jerk response to the issue you raise (a thread per object is not scalable). it certainly addresses this issue but intentionally or otherwise, it also resolves quite distinct concurrency issues. i tried to present an example of this in a previous message but its not easy, i.e. its stressing my ability to articulate. typical code from a multi-threaded development follows certain lines as a response to concurrency. classes are developed that are basically message processing threads and other classes are developed that encapsulate certain function and are synchronously called by the message processing class/thread. the latter can ignore concurrency if it is only accessed indirectly via the former. the ActiveObject pattern overlays nicely onto this "typical code". so when we refer to an "active object" or "inherited thread" its not (technically) anything from the pattern. it does closely resemble a servant. and a servant does not consume a platform thread. i believe that what everyone intuitively wants is the same (or very close) and that it is fulfilled by the definition of a servant. if that is so, then the number-of-threads issue is obviated. with a vague hope that it helps, the implementation that i am working with has two significant base classes, lets say "scheduler_base" and "servant_base". the "real" scheduler is a template with policy parameters for thread creation, message queue definition and processing. the template inherits from the base (of course :-). an active object would (most often) be derived from "servant_base". lastly, scheduler_base inherits from servant_base, i.e. scheduler is-a servant. a relationship missing from the original pattern. in my opinion. there seems to be some interest but not sure where everyone wants this to go? there was some excellent code from matt and a whole lot of quality discussion. this works for me :-) but tangible output is always nice. cheers, scott ps: now that i have converted a decent amount of code to active objects the result reminds me of doctor dolittle; its like talking to the instances ;-)
participants (11)
-
Andreas Huber
-
David Abrahams
-
Douglas Gregor
-
Jeff Garland
-
Jody Hagins
-
Matthew Vogt
-
Michael Glassford
-
Peter Dimov
-
scott
-
Sean Kelly
-
Sergey Kurdakov