Boost logo

Boost :

From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2005-12-15 20:48:06


Hi Christopher,

--- christopher baus <christopher_at_[hidden]> wrote:
<snip>
> I do think that Arkadily has a point. For better or worse,
> much of the programming world has been trained to think about
> sockets synchronously, and eventually boost/C++ should address
> this.

But the question is how this should be addressed :) I happen to
think that the fact many people have been trained to think about
sockets synchronously is most definitely for the worse. Of
course there are situations where synchronous is more
appropriate than asynchronous, but it's the lack of awareness of
asynchronous as an alternative that can lead to inferior design
choices.

> When that happens it would be nice to use the same fundamental
> types presented in asio, and these users shouldn't have to
> know about demuxers.

With asio, I was hoping to make asynchronous operations as
natural and easy to use as possible, compared to their
synchronous counterparts. I think that providing a
synchronous-only socket interface is counterproductive. It
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 just want to point out that async reading and writing could
> be a function of an async I/O demuxer and not the socket
> itself. The socket could be passed to the demuxer and not
> vice versa.

The above design is something I can fundamentally disagree with
;) That sort of design, in my opinion, relegates asynchronous
operations to "second class citizens".

Asynchronous operations are no less part of a socket interface
than their synchronous counterparts. A write operation sends the
same data on a socket whether it is performed synchronously or
asynchronously. It's simply that a synchronous call blocks the
calling thread until the operation completes, whereas an
asynchronous call executes on a logical background thread and
tells you when it is complete.

Another goal of asio is to provide a basis for further
abstraction. For this I believe it is important to provide a
clear correlation between the synchronous and asynchronous
operations. Consider a protocol where messages have a fixed
length header followed by a body, where the body length is
contained in the header. The synchronous read operation might
look something like:

  void read_message(Stream& s, message& m)
  {
    ... create buffer for header ...
    read(s, header_buffer);
    ... create buffer for body of correct size ...
    read(s, body_buffer);
    ... populate message structure ...
  }

The equivalent asynchronous code would be:

  void async_read_message(Stream& s, message& m, Handler h)
  {
    ... create buffer for header ...
    async_read(s, header_buffer, bind(header_handler ...));
  }

  void header_handler(error e, Stream& s, message& m, Handler h)
  {
    ... check for failure ...
    ... create buffer for body of correct size ...
    async_read(s, body_buffer, bind(body_handler ...));
  }

  void body_handler(error e, Stream& s, message& m, Handler h)
  {
    ... check for failure ...
    ... populate message structure ...
    h(e); // indicate that operation is complete
  }

There is a relatively straightforward mapping between one and
the other. In the future I want to exploit this mapping further
by investigating the use of expression templates (perhaps
similar to Boost.Lambda) to permit the encoding of a sequence of
operations in a synchronous programming style. The operations
could then be executed either synchronously or asynchronously as
needed.

Cheers,
Chris


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