From: Peter Dimov (pdimov_at_[hidden])
Date: 2005-04-23 07:25:52
Don G wrote:
>> The question is why do you need multiple network
>> objects at the client side.
> My sad story: Over the past couple years I've had the joy of writing
> some ActiveX controls that run in IE (please don't shoot; they were
> the good kind<g>). In doing so, I have been best served by not having
> any active stuff running behind the scenes, especially threads. The
> desire to keep a library of pure objects has flavored my choices
> When an ActiveX object dtor is called, I want _all_ activity related
> to that instance to stop. Other instances may be held by other
> threads and I don't want all interfaces to be thread-safe. Anyway,
> that is a big part of why I avoid designs that have significant
> apparatus globally managed.
This is a good point. I'll describe how I think your model is supposed to
operate, because I can't reconcile it with some of your later statements,
The network object owns the pending callback queue and the worker threads.
When this object is destroyed, all activity is cancelled, pending callbacks
are lost or delivered, and the worker threads are stopped.
> So, at one level, the serial line is just a stream. Over that stream,
> one can layer an entire network model, including "me" and "thee"
> addressing. :)
Yes. You do know that this applies for every stream, of course. You can have
a network_over_stream adaptor and layer a network over a TCP connection, a
named pipe or over stdin/stdout. This doesn't make any of these streams
networks, and neither is a communication port a network.
The network-over-stream is a good example that demonstrates the strength of
your network-centric design. Addresses are naturally network-dependent and
do not have a meaning outside of the context of a particular network.
This of course leads to the obvious question: which network gives me a
stream over COM1? LPT1? A named pipe? An arbitrary UNIX file descriptor?
> I'm not sure I understand the difference you are drawing between ":/"
> and "://". The way I read the URL/I syntax, many options will work. [...]
No, the problem is that you are abusing the URI syntax. :-)
An Universal Resource Identifier is universal. It is not context-dependent
and completely identifies a resource.
Your addresses are network-dependent and cannot be used outside of the
context of their network. They may look like URIs, but they are not.
>> I'm not sure. net::poll is specifically intended to
>> preserve the internal structure of your library. You
>> only need to defer dispatching the callbacks until
>> net::poll is called (unless net::async_poll is in
> I am not sure I understand your async_poll suggestion (sorry about
async_poll is basically what your library does at the moment. It acts as if
there were an implicit async_poll call after a network is created.
In a network-centric model, BTW, poll and async_poll would be member
functions of the network class.
> I agree that net::poll() would fit with a common desire to
> have single threaded network programs, but might complicate things
> where the program is a GUI. Integrating with the GUI loop is a study
> in compromise (at least for Windows).
So you just use async_poll, just as you do now.
>> It also gives you the freedom to make net::poll the
>> primary model since it maps very naturally to
>> select/epoll. But you aren't forced to do that.
> I like the idea of net::poll() for some uses, but it doesn't fit what
> I often need (GUI integration). It does fit with select/epoll
> especially on platforms where the number of objects that can go in an
> fd_set is > 64.
> I don't know if it was clear from previous posts, but I do have in
> mind a higher level net::poll() like library. The reason I prefer
> that approach to net::poll() is that not all async activities are
> network related. A timer comes to mind here. Also, the GUI event
> loop. Also, just plain "do this next, but not now" queuing. I would
> want the ability to have all that deliver out of the same pump as
> network completion callbacks.
I can't fit this into my understanding of how your library is organized.
Callback queues and worker threads are network-specific. You can't layer a
higher-level poll facility on top of these. I must be missing something.
> My current proposal does not include explicit support for this. With
> the general async facility I am describing, net::poll() would be
> relegated to only some pure network-only, apps that absolutely insist
> on the select w/no threads approach.
> I agree, but others don't. Some folks don't want any background
> threads; just a single thread doing one uber select/epoll call
> (again, for platforms that can handle it). The only way I can see to
> accommodate that is a different concrete network object. The ones I
> would write initially would probably not fit this desire, but again,
> the interface and behavior contract probably can.
My interpretation is somewhat different than yours. I believe that some
folks want to use select/epoll whenever this model is more efficient, not
just because it's uber or single-threaded.
>> That's the whole idea. When using net::poll the
>> context is the thread that called net::poll. When
>> using async_poll (your current modus operandi),
>> the context is an unspecified background thread.
>> The user is in control of the context.
> I am specifically concerned with the hypothetical protocol library
> author here more than the application author. If I want to write an
> SSL stream, for example, I need to know how my use of the real stream
> will behave and what I am allowed to do in the callback context.
> While the application layer may make the final call, that call cannot
> invalidate the contract assumed by the protocol library author.
It can't invalidate the contract. Your current contract is that callbacks
are run in an unspecified thread. With poll, the application layer can
specify the thread. I don't see how can this possibly contradict the
assumptions of the protocol library.
> - At the app layer, the developer sometimes wants to
> choose single threaded(!) vs. don't care but deliver it
> on this thread please vs. use whatever thread context
> is best + use my quad CPU's please + minimize context
> switches (aka "give me your best shot, I can take it").
Can you give an example of a developer that absolutely insists on a
single-threaded implementation (not interface)?
I think that the distinction is: invoke callbacks in whichever thread suits
you best vs invoke callbacks in _this_ thread please, my application is not
reentrant. And regardless of which I've chosen, give me your best shot under
these requirements. No need to confine yourself to a single thread/CPU
_unless this will be faster_.
> - Middle level protocol libraries (like SSL or HTTP)
> must not be presented with different behaviors from
> the abstract interfaces. If they followed the rules
> (TBD), they should continue to work regardless of a
> choice made by the application developer.
Do you have a specific behavior in mind?
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk