Boost logo

Boost :

From: Matthew Vogt (mvogt_at_[hidden])
Date: 2004-03-01 21:35:14


scott <scottw <at> qbik.com> writes:

> Hi Matthew,
>
> Hopefully my recent message (new subject "Reactive Objects") clears
> the air.

Yup. I'll reply to that when I've read a couple more times... :)

> > Yes. Although, the sender could bind a return address into
> > the call in this
> > model also - it would have to be the address of a method in
> > the sender. This
> > would allow the automatic routing that I think is preferable
> > to messages.
> > This model is still working by passing messages, mind, but
> > the messages have
> > extra data with them to skip the dispatch processing.
>
> Hmmmmm. We are either still confused or we have different targets.
> Since I exist in the former continuum, the following is mostly for me.
>
> If there were a callback (called by thread after de-queueing a
> message) that went something like;
>
> db_client::on_next( ... ) // User pressed the "next" button
> {
> if(db_server.next( current_record ) == END)
> {
> // Wrap to the beginning
> db_server.first( current_record );
> }
> }
>
> How do you "bind a return address" to the point just after the
> "call" to "db_server.next"? Even if you do manage this syntactically,
> is the call to "on_next" suspended somehow? Obviously the same
> "suspension" would have to occur for the call to "db_server.first".
>

You can't (as far as I know, anyway). So the return address has to be a
method in the object that invoked the call. The client has to be refactored
to (pseudo-code):

db_client::process_next( ... next_record )
{
  if ( next_record == END )
  {
    // Wrap to the beginning
    return_to( process_next ) = db_server.first( current_record );
  }
  else
  {
    ... // do something
  }
}

db_client::on_next( ... )
{
  return_to( process_next ) = db_server.next( current_record );
}

This assumes that the return_to<> proxy can be created to update the other
proxy (the method request emulator) to bind the return address...

> I suspect that you are thinking (and have been doing your best to
> tell me) that the "asynchronous calls" will be effected by the
> threads in each active object. They will simply "chain"?

Not sure what you mean by 'chain'...

> If that
> is the case then I see some difficulties. The least would be the
> loss of throughput relative to "true" async calls. More importantly
> I think you might be calling back into an object (e.g. the db_server
> calling a response method in a client) that otherwise has no
> idea that the original request has been completed. As a "model
> of operation" this seems at least as foreign as the "fully async"
> model that SDL pushes?
>

I don't think I mean what I think you think I mean. Taking away the proxies,
the above pseudo-code would become:

db_client::on_next( ... )
{
  //return_to( process_next ) = db_server.next( current_record );
  message m;
  m.sender = this;
  m.address = bind(&db_server_class::get_next_record, db_server);
  m.arg1 = current_record;
  m.return_address = bind(&db_client::process_next, this);

  db_server.enqueue_message(m);
}

and the underlying message_handler code (from which both the db_client and
db_server_class classes derive) looks like:

message_handler::process_message_queue()
{
  message& m = dequeue_message(); // client request

  if ( m.return_address )
  {
    message result;

    result.sender = this;
    result.address = m.return_address;
    result.arg1 = m.invoke();

    m.sender.enqueue_message(result);
  }
  else
  {
    m.invoke();
  }
}

In both cases, the objects are merely dequeueing messages and doing whatever
processing the message requires, possibly generating other messages as a result
(directly, as a return message, or indirectly as a side effect).

Therefore, it is fully asynch. The 'method request' interface is only being
used in the creation and binding of messages.

> In your version of things the sender is selecting the code to
> be executed in the recipient. This is the fundamental difference.
> In my version the client cannot assume anything about the receiver.
> There are perfectly valid examples of "active objects" in my ActiveWorld
> that _must_ be able to receive _anything_. One example is a proxy
> object that accepts any message and forwards it across a network
> connection to an active object in a remote process.
>

Yes - I was assuming a published interface from the (re)active objects, although
you do present a good example of somewhere this can't be done. For
this individual case, you can ditch the method-emulating proxies and deal
with the underlying message queues directly.

> Also, the active object may (or may not be a state machine.
> The sender (i.e. a client) cannot truly know which method to call
> as the correct method is state-dependent. The runtime switch issue
> that exists for this circumstance is similar to the issue that exists
> for selection of method call vs switching on message. One strategy involves
> knowledge of the recipient, the other doesnt. Well, other than that
> all active objects are capable of receiving messages

I hadn't realised how integral the state machine was to your design until I
read your other post. Still, if you are doing dispatch on both message code
and object state, it can be simplified to bind the message to a per-message
code dispatch function which then dispatches on object state.

Matt


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk