From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2005-12-19 19:33:54
--- Arkadiy Vertleyb <vertleyb_at_[hidden]> wrote:
> Could you provide some (high-level) justification of why it is
> beneficial to have a socket dependency upon a demuxer?
> Maybe I am missing something, but IMO such a dependency is
> unnatural even for asynchronous IO.
This has not come up in the discussion thus far, but the
dependency on the demuxer is required to enable an efficient and
portable implementation of asynchronous I/O. This is one of the
primary goals of asio. The asio interface has been designed to
reflect efficient asynchronous I/O mechanisms across major
Let's take the specific case of Windows, where asynchronous I/O
is implemented using I/O completion ports. Once a socket is
associated with an I/O completion port it cannot be
In asio, the demuxer represents the I/O completion port.
The asio interface enforces this association by constructing the
socket with its associated demuxer/IO-completion-port.
>From the point of view of the library user, any asynchronous
operations started on the socket will have the completion
handler delivered through the associated demuxer (as it is with
I/O completion ports).
Separating the asynchronous I/O operations from the socket class
would no longer enforce this requirement at compile time.
(That's even leaving aside questions about where the operation
> Hiding it behind default parameter, singleton,
> etc., just masks what I believe is a design problem.
> If you absolutely believe this dependency is necessary for
> async IO, having two separate classes, such as sync_socket and
> async_socket would be much cleaner. But again, I can't see
> what justifies such a dependency even for async IO.
So the question is really whether there should be separate sync
and async socket classes, versus a combined class as there is
now. I believe that, on balance, separate classes would be
harmful. Let's reiterate some of the points:
- Synchronous and asynchronous operations are essentially the
same, in that they perform the same operation and aim to
fulfil the same contract. How they differ is simply that one
blocks the current thread, whereas the other executes in a
background logical thread and tells you when it is complete. I
want there to be a clear mapping from one to the other.
- Separate classes reinforces the notion that synchronous
operations are somehow more useful for the ordinary
programmer, and that asynchronous is hard and best left in the
realm of the networking guru. I do not believe that
asynchronicity is difficult to use or understand, it is simply
that programmers often approach sockets with preconceived
ideas of how an API should behave. But I do believe that
separating the classes will continue the lack of awareness of
asynchronicity as an option, leading to the needless use of
- The greater number of classes and options will increase the
size of the library's interface.
- I have demonstrated that there is a use case for mixed-mode
applications. Predominantly synchronous designs can benefit
from localised asynchronicity. Asynchronous designs can be
simplified by selective use of synchronous calls.
- A line of reasoning has been presented which says that,
because files already have a synchronous-only interface and
could be given an asynchronous interface, sockets should also
have a synchronous-only interface. However, sockets are
inherently different to files due to the long timescales
involved in many operations. Developers will look for some
form of concurrency to address this, and I believe
asynchronicity *should* be promoted over threads as a
It is worth noting that even .NET combines the sync and async
socket operations on a single interface.
I do find that there is a compelling case for a synchronous-only
interface to sockets at the iostreams level. But that is because
of the established use and wide applicability of iostreams, not
because it is synchronous.
So let me turn the question around. Why must there be a
low-level synchronous-only interface at all? What benefits
will it bring? What use cases do you have that cannot be met by
a combined interface or an iostream interface?
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk