First of all thank you for posting a minimal, complete, and verifiable example.
It looks like your implementation of async_method() is missing one or
two executor_work_guard objects:
Per N4734[1] 13.2.7.10 Outstanding Work [async.reqmts.async.work]
1. Until the asynchronous operation has completed, the
asynchronous operation shall maintain:
(1.1) — an object work1 of type executor_work_guard, initialized
as work1(ex1), and where work1.owns_work() == true; and
(1.2) — an object work2 of type executor_work_guard, initialized
as work2(ex2), and where work2.owns_work() == true.
I don't think you can get away with just calling `post` from
`async_method` you need to write a "real" composed operation class
with all of the bells and whistles including forwarding of the
associated executor and associated allocator. In this class you can
store the two required executor_work_guard objects as data members.
A tutorial for writing composed operations may be found here:
Thanks
[1] <http://cplusplus.github.io/networking-ts/draft.pdf>
13.2.7.1 says
The life cycle of an asynchronous operation is comprised of the
following events and phases:
(2.1)
— Event 1: The asynchronous operation is started by a call to the
initiating function.
(2.2)
— Phase 1: The asynchronous operation is now outstanding.
(2.3)
— Event 2: The externally observable side effects of the asynchronous
operation, if any, are fully established.
The completion handler is submitted to an executor.
(2.4)
— Phase 2: The asynchronous operation is now completed.
By this definition of "completed" shouldn't my sample code be fine?
This is not supposed to be a composed operation.
In any case I was looking at basic_socket::async_connect() and I
noticed I was using async_completion differently. After changing
"boost::asio::async_completion<ConnectHandler, void(const
boost::system::error_code &)>" for
"boost::asio::async_completion<ConnectHandler,
void(boost::system::error_code)>" (error_code by value, not const
reference) my sample code has started working correctly.
I'm not sure I *really* understand what was going on (or if this
couldn't have been detected at compile time). But... it kind of makes
sense.
Networking.TS has unfortunately tied itself to executors, there was no need for that.
To be fair, it's probably easier to use libuv and put up with the loss of type safety. At least you'll beable to set timeouts properly.