立即启动协程 C++ asio

Tel*_*gar 6 c++ boost-asio

当使用预协程 asio 接口时,我可以在当前执行上下文(主函数)中调度一个异步函数,并让它在ctx.

#include <iostream>
#include <asio.hpp>
using namespace std;
using namespace literals;

int main() {
    asio::io_context ctx;
    asio::steady_timer t(ctx, 2s);
    asio::dispatch([&](){
        cout << "inside coro before wait" << endl;
        t.async_wait([](asio::error_code){
            cout << "inside coro after wait" << endl;
        });
    });
    cout << "starting ctx.run()" << endl;
    ctx.run();
}
Run Code Online (Sandbox Code Playgroud)
$ ./sol
inside coro before wait
starting ctx.run()
inside coro after wait
Run Code Online (Sandbox Code Playgroud)

我想用协程复制它,asio::awaitabledispatch不支持协程。

另一方面,co_spawn仅将协程添加到上下文中,并且不会立即启动它。

我可以使用ctx.poll()/ctx.run_one()但协程必须是唯一准备执行的协程,或者至少是第一个协程。

答案

如果我没有弄错的话,启动协程(从协程外部)的唯一方法是使用asio::co_spawn(executor, awaitable, token). 与 相比dispatchco_spawn接受一个 executor 作为参数,正如 @sehe 所说,dispatch使用关联的 executor。因此,要回答我关于如何立即启动协程的问题,就是在 中运行它asio::system_executor()

$ ./sol
inside coro before wait
starting ctx.run()
inside coro after wait
Run Code Online (Sandbox Code Playgroud)
$ ./sol
inside coro before wait
starting ctx.run()
inside coro after wait
Run Code Online (Sandbox Code Playgroud)

seh*_*ehe 3

该代码有多种方式无法执行其建议/您描述的操作:

asio::dispatch([](){
    // executes immediately
    asio::steady_timer t(ctx, 2s);
    t.async_wait([](){
        // executes in ctx.run()
    });
});
ctx.run();
Run Code Online (Sandbox Code Playgroud)
  • 永远不会等待2秒,因为t的析构函数在启动后会async_await 立即取消。

  • ctx显然是静态的或全局的,因为它没有被捕获

  • 完成处理程序没有所需的签名

  • 即使它正确地接受了一个error_code变量,它也不会 在 ctx.run() 中执行[s]”,因为在lambda 的关联执行器dispatch上进行分派。由于没有其他关联,因此将默认为 的默认构造实例。asio::system_executor

    请参阅例如std::boost::asio::post /dispatch 使用哪个 io_context?

问: 另一方面,asio::co_spawn 仅将协程添加到上下文中,并且不会立即启动它。

我认为这也不准确。正如您提到的,您给出的代码无效(因为post不支持协程)。当固定使用时co_spawn,我们可以显示它在里面运行ctx.run()

#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using namespace std::chrono_literals;

int main() {
    asio::io_context ctx;
    asio::co_spawn(
        ctx,
        []() -> asio::awaitable<void> {
            auto ex = co_await asio::this_coro::executor;
            asio::steady_timer t(ex, 2s);
            co_await t.async_wait(asio::use_awaitable);
            std::cout << "inside ctx.run()" << std::endl;
            // co_return;
        },
        asio::detached);

    std::cout << "before ctx.run()" << std::endl;
    ctx.run();
    std::cout << "after ctx.run()" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

印刷

在此输入图像描述

我真的认为99%的问题都取决于这些错误的前提,所以我会在阐述之前等待你的反应。

更新

想得更久,我想你可能会对这个问题有不同的看法:asio How to change the executor inside an waiting? ,但没有意识到您无意中使用了系统上下文进行调度。

下面是(关联的)执行器如何与协程简历交互的更全面的说明:全尺寸

在此输入图像描述

另请注意,当工作仅在系统上下文中挂起时,如何需要工作防护来避免 ctx 耗尽工作。

我强烈建议不要依赖系统上下文,但是这个插图应该可以帮助您连接所有点?