Boost logo

Boost :

From: Carlo Wood (carlo_at_[hidden])
Date: 2004-09-13 06:36:32


On Sun, Sep 12, 2004 at 10:18:05PM -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.

I have no problem whatsoever to stick to a single thread if you
are right. But, I am convinced it will not be possible
to do this without threads. If you know otherwise then I suggest
you tell me the solution for problems I will run into when
trying to code this within one thread.

> > 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.

I have no problem not supporting winsock1, or with at most 64 sockets.
But, it could be supported without that the user even KNOWS it created
additional threads - why would it be bad to do that?

> 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.

Why not? This is what libACE does too; I am interested to hear why
you think it is wrong.

> > 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.

But while that might be possible on GNU/Linux, it might be impossible
on windows (for example). The demand to provide a portable interface
forces us to create (hidden) threads therefore. If a user decided that
he only needs one thread and the library is not allowed to implement
the requested interface by running two or more threads internally,
then how can I implement an interface that allows one to wait for
events on 100 sockets, a timer, a few named pipes, a fifo and some
large diskfile I/O at the same time? That is possible on linux,
but I failed to figure out how this can be done on windows :/

> 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.

Agreed.

> In
> addition, the design should be as unsophisticated as possible. In
> particular, event notification might be simple functors (no 'observer'
> frameworks)

How would one use functors to wait for the plethora of different events
to be handled? Surely not as template parameter of the multiplexor class.
You mean as template parameter of methods of that class? That would
still involve a dereference (some virtual function) in the end, somewhere
imho; you don't seem to gain anything from this in terms of inlining
(the main reason for functors I thought). Templates do however tend
to cause a code bloat :/

> 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.

Hmm. I agree with the efficiency in terms of cpu. But as always,
storage efficiency and cpu efficiency are eachothers counter parts.
You cannot persuade both at the same time. I think that embedded applications
need a different approach - they are a different field. It will not
necessarily be possible to serve both: high performance, real time
server applications AND embedded applications at the same time. In
that case I will choose for the high-end server applications at any
time :/ (cause that is were my personal interests are).

> 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.

I still think we will need threads - not only internally but even
as part of the interface to support users that WANT to write
multi-threaded applications.

Consider a user who has two threads running and he wants to wait
for events in both threads. He will then need a 'Reactor' object
for both threads: both threads will need their own 'main loop'.
Supporting that (and we have to support it imho) means that the
library is thread aware. I think we have to depend on Boost.Thread
as soon as threads are being used; I am not willing duplicate
the code from Boost.Thread inside Boost.Multiplexor, just to be
independend of of Boost.Thread.

-- 
Carlo Wood <carlo_at_[hidden]>

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