Boost logo

Boost Users :

Subject: Re: [Boost-users] [asio] Grasping the proto-typical socket server
From: Anthony Foiani (tkil_at_[hidden])
Date: 2013-06-24 23:48:03


Michael Powell <mwpowellhtx_at_[hidden]> writes:

> I see three primary abstractions, the server itself, with endpoint
> binding, socket connection acceptor, so far so good. Then there's a
> connection, which is a sort of io_service to socket adapter. Followed
> closely by a session concern, where reads and writes are actually
> performed.
>
> Studying the examples, however, it seems to me that by design
> io_service wants to be *the* first class citizen that runs, with
> asynchronous callbacks being the mode of choice.

Well, the ASIO examples would stress this aspect. I don't believe
it's required, however, and I feel that there is plenty of work that
can be done before and after io_service::run() is called.

> How might we go about mixing this code, presumably in the main
> thread (?), with any worker service-oriented thread that might be
> going on. For instance, I start a thread and wait for it to finish
> and rejoin for a main service loop.

Fundamentally, you are welcome to do io_service::run in only one
thread amongst all the threads running in your project. (See below --
I actually have a multitude of io_services running, but not at all
one-to-one with threads!)

> Socket connection sessions are secondary to this service behavior
> taking place IMO. If a client connects, great, we'll interact with
> it. If not, that should be transparent to the application. Possibly
> session is a second thread worker with a thread-local-scope
> io_service, that we pub/sub messages to the main service loop.
>
> Thoughts on this type of approach?

The following architecture is working fairly well for me:

1. Main thread: handles setup, launching primary service threads (data
   acquisition, data writer, web server, scheduler, usb monitor, etc),
   and cleanup after the main threads are done.

2. Web server: one thread is the "server thread" and handles all
   connection listening / accepts. The server code also starts a
   number of client threads, which exist to service individual client
   requests.

3. If a client request affects other parts of the system, then that
   other part is notified in some thread-safe manner (atomics, work
   queues, etc)

I would probably do things a little differently now, but I was lead
down this path because this device has a "soft real-time". As such, I
didn't want to mix tasks servicing the acquisition interrupt (10s of
milliseconds tolerance) with tasks handling, e.g., the web UI or the
FTP client (dozens of seconds tolerance).

Now that I have a better grasp of how threads and ASIO can interact, I
could probably reduce the number of threads I'm running and just
schedule various bits of work against a thread pool. Too late to
change this design, though.

Not the only way to do it, but neither is the methods used in the ASIO
examples. In particular, there's nothing keeping you from starting a
dozen threads but only calling io_service::run() in six of them.

Hope this helps.

Best regards,
Anthony Foiani


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net