|
Boost : |
From: Jeff Garland (jeff_at_[hidden])
Date: 2004-09-12 23:21:48
On Sun, 12 Sep 2004 22:18:05 -0500, Aaron W. LaFramboise wrote
> Carlo Wood wrote:
> >>2. It is unavoidable that this library uses threads.
>
> I disagree strongly. I think spawning additional threads is both
> unnecessary and undesirable.
My guess is that Carlo was saying that the library must be thread-safe at a
minimum. That is, I could, for example add/release an event callback from a
different thread than the multiplexor is running in. But even if he meant
more, my take is we might want some threading capabilities...see below.
> > 1) On windows we have a limitation of at most 64 'Event' objects
> > that can be 'waited' for at a time. This is not enough
> > for large server applications that might need thousands
> > of TCP/IP sockets.
>
> In the case of sockets, Winsock has other mechanisms for scaling in this
> respect, such as I/O completion routines. On pre-Winsock2 platforms,
> which hopefully are dwindling, I don't think falling back to the 64
> handle limit will be a problem.
It's easy to blow this if you start monitoring any significant hardware.
Start monitoring some serial ports and setting various timeouts associated
with those prots and you can run into troulble easily. In fact, timers is a
big problem -- you need to have a smart queing implementation that keeps the
number of timers down to the bare minimum....
> It seems unlikely to me that there are many cases were the limit
> would be exceeded. However, in those cases, I don't think it would
> be a problem if the multiplex user were required to create another
> thread, and another multiplex. I don't think the multiplex should
> do this.
Well, it's ugly for the user because it's tough to predict when you are going
to hit the 64. So I disagree, I'd like to see the user shielded from this issue.
> > 2) On windows there are different types of handles/events. It
> > seems to make a lot more sense to use different threads
> > to wait for different types. For example, there is a
> > WSAWaitForMultipleObjects (for sockets) and a WaitForMultipleObjects
> > that allows one to wait for arbitrary events (but not socket
> > events(?)). More in general however - there seems to be
> > a need to use different ways to demultiplex and handle
> > different types - even if the handles of all different types
> > are the same (ie, 'int' on UNIX). Consider the major
> > difference between a listen socket, a very busy UDP socket
> > and a very busy memory mapped filedescriptor. It might be
> > easier to regular priority issues between the different types
> > by putting their dispatchers in separate threads.
> > Note however that I DO think that the callback functions
> > for each event (that is, the moment we start calling IOstream
> > functions) should happen in the same thread again; this
> > new library should shield the use of threads for the user
> > as much as possible!
>
> I also don't think the multiplex should do this. Boost shouldn't
> second-guess what the user is trying to do. If the user knows he needs
> two separate threads to handle two separate resources, then let the user
> create two threads and put a multiplex in each.
Well, I think there might need to be some interface here. For example, it
would be nice for the multiplexor would have a pool of threads and dispatch
each event to execute in a thread. The size of that pool might be '0' in
which case the multiplexor uses its' thread to dispatch in -- hence
degenerating into a single-threaded arrangement.
> By _multiplex_ I mean the class (or whatever entity) that implements
> the core of the demultiplexing of various resources. (I'm using
> this name because thats what I called it in my own library.) I
> beleive this class should have these characteristics:
>
> 1) Minimal - It should handle every sort of event that might need to
> be handled, but nothing more. More complex logic, such as pooling
> and balancing, should be handled elsewhere, possibly by a derived
> class. In addition, the design should be as unsophisticated as
> possible. In particular, event notification might be simple
> functors (no 'observer' frameworks)
I'd like to see a template approach (see below) that allows new multiplexor
and event handler types to be added in as they are developed. The core then
just sets up and manages the core of the dispatching.
> 2) Efficient - For many applications, performance will be paramount.
> Many asynchronous algorithms will depend on the multiplex core having
> negligable overhead, and Boost should not disappoint. As it may be a
> crucial building block of nearly any real-world program, it should also
> be storage efficient, to not rule out application in embedded areas.
Agreed. BTW, I'd like to see an attempt to remove all virtual methods from
the mix.
> 3) Compatible - See
> http://article.gmane.org/gmane.comp.lib.boost.devel/109475
>
> It is my opinion, in fact, that this multiplex class should be in its
> own library, isolated from any other particular library that would
> depend on it. In other words, it wouldn't be any more coupled with I/O
> than it would be with Boost.Thread or date_time.
Well, I'll disagree with this one as well. I think it should be coupled with
both thread and date_time, since you picked those two ;-)
Here's why. I think the interface should look something like this:
class mutliplexor {
public:
//returns a unique event handler id
template<class EventHandler, class EventMultiplexor>
boost::int32_t
register(EventHandler eh, EventMultiplexor em, unsigned int priority);
void remove(boost::int32_t event_handler_id);
void suspend(boost::int32_t event_handler_id);
void run_event_loop(time_duration td = time_duration(pos_infinity));
void end_event_loop(time_duration td = time_duration(pos_infinity));
};
Note that the amount of time to run the event loop is specified as a
time_duration which allows things like 'pos_infinity' or run forever to be
specified more cleanly than the typical interface which passes '0' meaning run
forever. Now I can write code that looks like and it's perfectly clear what
it means:
multiplexor m(...); //setup
while (!done) {
m.run_event_loop(seconds(1));
//do other stuff like set done
}
So there's the hook to date_time. BTW, for this part of date_time you only
need headers -- you don't need to link the lib.
As for boost.thread, that will be needed because the mutliplexor implemenation
of register will need to manage a list of event handlers and will need to be
capable of dealing with the remove, suspend, and register running in different
user threads. This means it will need to lock. So even if you argue away
date-time I don't see how you avoid boost.thread.
Jeff
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk