A currently running handler is considered work, so you don't need the second guard, because before the handler is dispatched, it's the timer's responsibility to maintain the guard for ctx2. After it calls `ctx.get_executor().dispatch()`, it will reset the guard, but the context will not stop until the handler is executed and returns.

On Mon, Dec 17, 2018 at 11:49 PM Cristian Morales Vega <cristian@samknows.com> wrote:
On Sat, 15 Dec 2018 at 21:21, Damian Jarek <damian.jarek93@gmail.com> wrote:
> As for the echo example in Beast: looks to me like there is a work guard for the I/O executor in state of the echo_op, so it seems to be correct.

What I'm concerned about now is the lack of a work guard for the
Executor associated with the CompletionHandler.

I have modified your example here
https://wandbox.org/permlink/IwmegLNlAKPs9tDP . It does work without
the second work guard, but not sure why. I'm concerned about the work
count reaching zero in the fourth output line, before the first
"Completion Handler called".
https://www.boost.org/doc/libs/1_69_0/doc/html/boost_asio/reference/io_context__executor_type/on_work_finished.html
says: "Once the count of unfinished work reaches zero, the io_context
is stopped and the run() and run_one() functions may exit." So ASIO
would have been free to stop ctx2 there, right?