
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org]On Behalf Of Matthew Vogt
Yep, there's gotta be mutexes somewhere.
The mechanism you're referring to is the task_queue of fully-parameterised method invocations? So, how precisely does this work? Say I have a scheduler that has performed some work via a method in a servant S, and that method produced a result of type int. I want to return that result to the caller C, but the caller may not be threaded (may not be associated with any scheduler). Does that mean that instead of queueing the response to the object, I will perform some type of registered action in C, in the same thread context as the method invocation of S?
Damn. I can see why you ask the questions that you are asking but the answers are very messy. I suspect it may be best to half-answer within the scope of your active<object> and then try to explain the "signal processing" equivalent. At the point where the scheduler is holding the result of type int, it needs to be able to "deliver" it to the caller. The only way it can do this is call a method on the appropriate object (instance) passing the results. Which method and which object? The scheduler can only get these from the queued task, i.e. the task must hold the method-to-run and pointers necessary for the return delivery. This method will be another proxy (e.g. non_void_with_param_returned) that in turn, queues the result. This decouples the scheduler from the recipient of the results; eventually the thread working on that task list will reach the "results task" and will run that. How does the object and method address get in the task object? You may well ask and this was (some of) the reason for my initial response. A by-product of working on "active objects" is a set of classes/templates that constitute a little thread-toolkit. This toolkit should facillitate the design and implementation of pretty much any snarling, thread-beast; if that is what you need. The "damn" part of my response stems from the fact that I believe the "Method Request" model is not viable as a model of execution for the thread toolkit. It is simply wrong and bending it to this task is a deadend. In signal processing the equivalent to "Method Request" is "send". This primitive takes an object to send and the address of the destination (e.g. an active<object>); send( int_results, calling_object ) These calls are made from within the methods that you already have working, i.e. the non-proxy _real_ methods. The trick with "send" is that it can be coded to populate the "task" with all the appropriate object and member pointers so that the receiving thread knows where it came from. Pretty typical SDL classes will look like; struct servant : { void send( signal_base &, servant_address ); }; struct db_slave : public servant { // Example only!!! void operator()( signal_base &s ) { switch( s.code() ) { case int_results: send( other_thing, third_party ); break; .. } } servant::send( signal_base &b, servant_address a ) { task t; // Pseudo only matt! t.message = b; // Payload t.source = this; // Return address .. a.queue( t ); // Again - just pseudo } I really hope this helps because I can see the inductive leap required to get over the chasm of despair. I only have one more esoteric observation to make. The "Method Request" model of execution is nice and familiar to us. It works brilliantly - mostly. Return addresses are managed automagically for us. But return addresses on a CPU stack are pretty meaningless when it comes to inter-thread communication. With the "Method Request" model we are trying to "call" across thread boundaries - IMHO thats just wrong. The signal processing model (once implemented) automanages a diferent type of address. A type of address that can be meaningful with reference to multi-threading. With a bunch more scaffolding this is what my reactive_object code looks like; int db_interface::transition( machine_state<READY>, typed_bind<interface_open> & ) { client.insert( sender() ); send( status, sender() ); return READY; } There is a whole lot of background missing here but hopefully there are some key elements that reinforce this alternate "model of execution". Some notes; db_interface: the class derived from scheduler (i.e. its a thread) and servant transition: overloaded name that handles different state+message combos interface_open: the closest thing to a "method" client: a set<> of servant_addresses send: the signal processing primitive status: an object suitable for sending, like "interface_open" sender(): the address of the object that sent the "interface_open" and caused this transition to run. READY: one of several defined machine states (enum) <sigh> Apologies if this is all badly presented. I have a huge body of code from which the ActiveObject portion would be impossible to remove. A major reason for starting or contributing to this thread is that I think my existing code desparately needs boostifying and the best way (or even a good way) is beyond me. Hence our messages. Hope this was useful. I suspect your right and I should start with another subject. After thinking long and hard about the most constructive approach. Hmmmmmmmm. Cheers, Scott ps: the sample code from mark blewett looks very promising?