On Thu, Jul 26, 2018 at 7:23 AM, Bjorn Reese via Boost-users
The post operation is handed off to the executor (13.23/6.3) so I would assume that the definition of "outstanding work" in 14.2 rather than 13.2.7.10 applies.
Right, so we know that `post` will construct executor_work_guard for the executor associated with a completion handler. And we know that the asynchronous operation is then responsible for constructing the executor_work_guard for the executor associated with the I/O object (in this case it is an object of type io_context::executor_type). If the completion handler has no associated executor, for example if it is a lambda or a bind wrapper, then the executor of the I/O context will be used (assuming the 2-arg version of `post` is called, which is required for correctness), and everything will seem to work even without the second work guard. However, if the completion handler has an associated executor, then omitting the second work guard results in an io_context with no outstanding work. Therefore, io_context::run returns immediately, and the completion handler is not invoked. This is what I see in Visual Studio. Linux users may see a different result on account of some implementation differences. Stackful coroutines launched with `spawn` have an explicit `strand`, which means the associated executor is NOT the same as the executor for the I/O context upon which the strand was launched. Therefore, omitting the executor_work_guard from an asynchronous operation which only calls `post` will not meet the asynchronous requirements for the case where the completion handler is a stackful coroutine. If anything, this just highlights the complexity of [networking.ts]. Users will definitely be making these mistakes repeatedly, especially the one where the 1-arg version of `post` is called instead of the 2-arg version. Thanks