Merge most of Networking TS into C++ Working Draft

Doc. No.: D1259R1
Date: 2018-11-04
Reply to: Detlef Vollmann, dv@vollmann.ch
Audience: SG1, LEWG, WG21

Merge most of Networking TS into C++ Working Draft

Introduction

The Networking TS grew out of Boost::ASIO and has got a lot of usage experience as part of Boost and in standalone implementations of the TS. Most of the Networking TS is uncontroversial.

One specific part of the Networking TS however clashes with the executor work in SG1. The executor work from SG1 is not yet ready to be merged into the C++ working paper. So this part of the Networking TS should not be merged. But most of the Networking TS can work without an explicitly specified executor model. This paper proposes to merge the executor independent parts of the Networking TS into the C++ working paper and solve any open issues on the Networking TS inside the C++ working paper.

Functionality to be Merged

Without the executor parts not all of the functionality of the TS will be available from the specification in the C++ WD.

This section tries to provide an overview of what functionality is merged and what is left out.

Summary

The Networking TS can be viewed as three separate parts:

This proposal merges all of the actual networking part, most of the continuation part (not uses_future) and nothing of the executor part.

Defining own execution contexts (based on io_context) is not available with the proposed subset and using strand is also not possible, but all of the networking operations (synchronous and asynchronous) are merged.

Details

I have myself not worked with any implementation of the Networking TS but with boost::asio and Chris Kohlhoff’s ASIO implementation available at http://github.com/chriskohlhoff/asio (because they provide useful additional functionality for Posix systems). Of the real applications (not toy projects to try some features) most would be possible with the proposed subset, but not all of them.

But to look at the features in more detail, I’ll use the examples from Chris in his github repo.

get_executor

When looking though Chris’ examples most of them work completely within the subset to be merged. Of those examples that don’t work without change most would fail because the use of get_executor(). Some of the calls to get_executor() are probably just out of habit (e.g. in the constructor of server in cpp03/porthopper/server.cpp), others are to avoid storing a reference or pointer to the io_context in an object if it’s already stored inside of e.g. an acceptor subobject anyway. These examples could simply be rewritten not to use get_executor() without change in functionality (though at the cost of an additional pointer inside the objects).

Calls that can’t be rewritten without affecting the functionality are the cases where there actually are multiple executors and it’s important to pick the right one. Probably the only important case here is strand.

strand

The Networking TS provides a class strand to serialize specific I/O operations based on io_context if io_context itself uses multiple threads.

strand is used in several examples. One of them is a multithreaded HTTP server in cpp03/http/server3. (Please note that the actual interface for strand differ between Chris’ implementation and the Networking TS, but the semantics are the same).

strand is an executor and as such not part of the proposed subset.

post

As being part of the main executor interface, post() is also not part of the proposed subset.

From a network perspective post() can be used to execute arbitrary functions asynchronously. One example that uses this is cpp03/chat/chat_client.cpp, which uses post() to put the actual function invocation in the queue at a more appropriate place. The example could be simply rewritten to not use post() without loss of functionality.

Another example is cpp03/serialization/connection.hpp, where post() is used to raise an error asynchronously.

Own executor

The only example that uses a custom executor in a networking environment is invocation/prioritised_handlers.cpp. This is an example for which the executor interface of the Networking TS exists and therefore is not part of the proposed subset.

Breakdown

Most examples just work, for others (get_executor()) some modifications are required. But of course, some functionality is not possible with the proposed subset.

The purpose of this proposal is to provide as much functionality as possible without interfering with any future executor interface in C++. post() and get_executor() in a minimal version would probably not cause any trouble for future executors.

strand in it’s current form definitely interferes. While it’s a convenient mechanism to make network applications scalable on parallel hardware, essentially the same effect can be implemented manually. Should a convenient synchronization mechanism be required now, something like a stripped down version of strand inside io_context might be possible without having too much inconsistency in future versions of C++.

Wording Overview

The proposal is to merge the Networking TS into the C++ working paper with the following changes: