c++boostboost-asioexecutorc++-coroutine

What executor does co_await boost::asio::this_coro::executor produce?


The documentation of boost::asio::this_coro::executor states that it is an

Awaitable object that returns the executor of the current coroutine.

To me this seems somewhat vague as soon as multiple Executors come into play; I assumed that co_awaiting it would provide the Executor the coroutine is currently executed on, i.e. I expected the assertion in this snipped to succeed:

boost::asio::io_context ioc;
auto io_ex = ioc.get_executor();

boost::asio::co_spawn(io_ex,
    [&]() -> boost::asio::awaitable<void> {
        
        auto switch_strand = boost::asio::make_strand(io_ex);
        co_await boost::asio::post(switch_strand, boost::asio::use_awaitable);
        assert(switch_strand == co_await boost::asio::this_coro::executor);
    },
    boost::asio::detached);

ioc.run();

However it turns out that, even after the post to switch_strand, io_ex == co_await boost::asio::this_coro::executor. Why does that happen? Will co_await boost::asio::this_coro::executor always produce the Executor the coroutine was originally co_spawned on, regardless of whether I switch to any other Executor within the coroutine? Does the call to post with switch_strand even "switch to any other Executor within the coroutine"?


Solution

  • The executor is a property of the coroutine. This why you can query the awaitable's promise type using the transformable (this_coro::executor). There might even be a conscious design choice that opted for

     auto ex = co_await this_coro::executor; // this syntax
    

    over

     auto ex = co_await this_coro::executor(); // instead of this syntax
    

    as opposed to other interactive transformation.

    Why does that happen?

    That's just how it was designed. In most senses, coroutines are self-modifying continuations. Continuations are handlers. Handlers can have associated executors. When you co_spawn(ex, foo, ...) you ask all these continuations to bind to ex.

    See also code comments

    Will co_await boost::asio::this_coro::executor always produce the Executor the coroutine was originally co_spawned on

    Yes. See also transform in code

    regardless of whether I switch to any other Executor within the coroutine? Does the call to post with switch_strand even "switch to any other Executor within the coroutine"?

    Yes and no: