首页 > 解决方案 > 如何使用 Handler 和 boost::asio::async_result

问题描述

如何使用 boost::asio::async_result,为什么我的代码崩溃(被信号 11:SIGSEGV 中断)

using ReadSignature = void(int);
template <class CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken , ReadSignature)
AsyncRead(boost::asio::io_service* ios,CompletionToken&& token) {
  using Handler = typename boost::asio::handler_type<CompletionToken,
                                                 ReadSignature>::type;
  Handler handler(std::forward<CompletionToken>(token));
  boost::asio::async_result<Handler> result(handler);

  std::cout << std::time(nullptr) << ":before thread" << std::endl;

  std::thread thread([ios,&handler]() {
    std::cout << std::time(nullptr) << ":run in thread before sleep"<< std::endl;
    sleep(5);
    std::cout << std::time(nullptr) << ":run in thread after sleep"<< std::endl;
    std::cout << std::time(nullptr) << ":run in thread before cb" << std::endl;
    ios->post([&handler](){
      handler(2);
    });
    std::cout << std::time(nullptr) << ":run in thread after cb"<<std::endl;
  });
  thread.detach();
  return result.get();
}

int main(int argc, char** argv) {
  boost::asio::io_service s;
  boost::asio::io_service::work worker(s);
  boost::asio::spawn(s,[&s](boost::asio::yield_context yield){
    boost::system::error_code er;
    int val=AsyncRead(&s,yield[er]);
    std::cout << std::time(nullptr) <<"get:"<<val<< "" << std::endl;
  });

  s.run();
  return 0;
}

我期望:返回 result.get(); 将产生纤维,值 2 将得到。但代码崩溃:(被信号 11 中断:SIGSEGV),因为 handler.ec 为空。

标签: c++boost-asio

解决方案


这样

ios->post([&handler](){
      handler(2);
    });

您创建排队的 lambda io_service。这个闭包在内部执行io_service::run。您通过引用捕获handler本地内部AsyncRead。何时handler(2)调用

AsyncRead(&s,yield[er]);

协程在上面的行中恢复,result.get()从调用AsyncReadAsyncRead结束和处理程序作为局部变量被破坏,但执行的闭包io_service::run仍然引用这个变量 - 未定义的行为。

您需要按值捕获处理程序,将其移动到线程和 lambda 中:

  std::thread thread([ios,handler = std::move(handler)]() {
    std::cout << std::time(nullptr) << ":run in thread before sleep"<< std::endl;
    sleep(5);
    std::cout << std::time(nullptr) << ":run in thread after sleep"<< std::endl;
    std::cout << std::time(nullptr) << ":run in thread before cb" << std::endl;
    ios->post([handler = std::move(handler)]() mutable {
      handler(2);
    });
    std::cout << std::time(nullptr) << ":run in thread after cb"<<std::endl;
  });

推荐阅读