gpt4 book ai didi

c++ - 想知道为什么我不能只为协程捕获 asio::handler_type 的引用

转载 作者:行者123 更新时间:2023-12-02 10:24:55 24 4
gpt4 key购买 nike

我正在使用协程玩 asio,并想测试如何调用异步函数。我有以下代码:

void async_foo(boost::asio::io_service& io_service, boost::asio::yield_context& yield)
{
using handler_type = boost::asio::handler_type<decltype(yield), void()>::type;

handler_type handler(std::forward<handler_type>(yield));
boost::asio::async_result<decltype(handler)> result(handler);

auto timer(std::make_shared<boost::asio::deadline_timer>(io_service, boost::posix_time::seconds(1)));
// the program crashes if I use &handler here
timer->async_wait([&handler](const boost::system::error_code) {
std::cout << "enter" << std::endl;
handler();
std::cout << "done" << std::endl;
});
result.get();

std::cout << "function finished" << std::endl;

return;
}

int main()
{
boost::asio::io_service io_service;

boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield) {
std::cout << "hello" << std::endl;
async_foo(io_service, yield);
std::cout << "world" << std::endl;
});
io_service.run();
return 0;
}

奇怪的是,如果我将 &handler 放在捕获列表中,执行流程将会困惑,然后会遇到段错误。但是如果我使用“处理程序”代替它运行没有任何问题(那么我当然需要在 lambda 中的拷贝)。

搜索了一圈,找不到任何相关的东西。提前感谢您的帮助。

最佳答案

正如 Tanner 很好地解释 here :

  • While spawn() adds work to the io_service (a handler that will start and jump to the coroutine), the coroutine itself is not work. To prevent the io_service event loop from ending while a coroutine is outstanding, it may be necessary to add work to the io_service before yielding.


如果在 run() 之后添加额外的跟踪行:
io_service.run();
std::cout << "BYE" << std::endl;

然后,运行几次,直到你有幸没有提前获得 SEGV,你可以看到如下输出:
hello
enter
done
BYE

实际上,io_service 返回,破坏了挂起的操作/处理程序,这也破坏了 coro¹ 的堆栈上下文。展开该堆栈会破坏该堆栈上的(本地)变量:
  • 处理程序
  • 结果
  • 计时器

  • 自从 timer未在 async_wait 的完成处理程序中捕获,计时器被简单地取消,但仍然尝试调用现在引用现已失效的堆栈变量 handler 的完成处理程序.

    复制 handler显然²确实让 coro 活着。

    回答核心问题 “并且想测试如何调用异步函数” 我建议使用更简单的成语:
    void async_foo(boost::asio::io_service& io_service, boost::asio::yield_context& yield)
    {
    boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(1));
    boost::system::error_code ec;

    timer.async_wait(yield[ec]);

    看到它 Live On Coliru

    ¹ -fsanitize=address证实了这一点
    ² 我知道它包含一个 weak_ptr到协程上下文,所以也许 Asio 在内部将其锁定到 shared_ptr ,我自己也不太清楚那些实现细节

    关于c++ - 想知道为什么我不能只为协程捕获 asio::handler_type 的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43403896/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com