
Christopher Kohlhoff <chris <at> kohlhoff.com> writes:
--- "Aaron W. LaFramboise" <aaronrabiddog51 <at> aaronwl.com> wrote:
If a demultiplexor library espoused one particular paradigm, it would be come useless to other incompatible paradigms.
Perhaps, but my experience in using asio (as opposed to writing it) has been that:
- A proactive interface is all that I have needed for sockets. - Other reactive or even blocking interfaces can generally be efficiently wrapped by proactive ones.
Thats fine as far as it goes. But I also think Aarons points re many factors affecting the choice of paradigm are equally valid.
But should that not be sufficient, I should point out that the demuxer in asio is extensible using a similar idea to std::locale's facets. So it is possible to override the implementation of a socket, or to even include a entirely new reactive-based resource.
It isn't clear to me how this is better than Aarons separation of the (de)multiplexor and the socket (or whatever) object, with the binding to a demultiplexor being relatively late. A proactive socket could easily enough be written to work with a proactive demultiplexor. The end effect, if I understand Aaron's proposal correctly, is a very flexible and easily extended design, that doesn't in any way preclude anything that your library implements (in fact I would think most of the implementation could be retained?).
In particular, it is up to objects themselves to implement the 'hooks' that their users may use, which might be proactive, reactive, or something else.
It is my feeling that attempting to define a demultiplexing interface in such a way is drawing the line of abstraction too low. However perhaps we are talking about different things :)
I think the demultiplexor (please can we use a better name for this when it is really so generic - maybe just "notifier") must have no idea what it is notifying the handler of if it is to be possible to make this truly generic. The fact that a notifier for proactor/aio may be almost invisible (built into the system) doesn't make all of this irrelevant. The binding of the handler to the notifier is still relevant - if only for cancellation. To implement proactor, there needs to be some way to convey to a handler what it was that just completed. But I don't see that as being any different to the other higher-level notifications Aaron suggest can be implemented by layering. That is, at the lowest layer, the notifier itself simply knows that some wrapped system object has notified. The handler for the system object (eg a signal handler) is then responsible for mapping this to the higher level interface. Because something like an async read request only makes sense for certain objects, it is a member function in Aarons model (if I'm understanding correctly). Something like (very sketchy, generics left out): class aio_rd_req; // encapsulates messy aio request context stuff socket::async_read(char *buf, size_t len, handler h) { aio_read(aio_rd_req::make(this,buf,len,h).iocbp()); } aio_rd_req::handle_completion() { m_handler(m_iocb.aio_buf, aio_return(&m_iocp)); delete this; } Is that so bad or so vastly different to how asio does it? Side note on names: Here asio stands for Australian Security Intelligence Organisation - sort of like the CIA :-)
My focus in asio has been on defining a C++ interface for using sockets or other OS objects asynchronously, but while leaving maximum freedom for the implementor (i.e. me until now) to use the best mechanism for a particular platform by default, whether that be native async I/O or a reactor-based solution.
Do you assume one or the other must be the best on a platform, or do you allow a "mix and match" approach? Platform quirks that result in aio working for some types of objects, and select/poll for others, plus the issue of whether proactive or reactive style makes sense in a given app may mean that the goals of efficieincy and portability fight each other. An approach where the code will fail to compile because there is no specialisation for a particular event source (eg socket) using notifier type X (eg aio) is not a bad thing. The ability to chose between notifiers that are portable but possibly inefficient on some platforms and those that will simply refuse to work if they are not efficeintly implementable is a nice feature. Extending the model to support a wider variety of event sources is bound to introduce further portability issues in terms of which event sources even exist on some platforms, as well as which notifiers work with them. Clearly some uber-notifier allowing a wide mix of event types (this is likely to be quite inefficient even without considering portability) should be provided for in the design, but it shouldn't be the only choice. Regards Darryl.