boost :: asio :: spawn和socket :: async_receive_from导致程序崩溃

时间:2018-10-12 16:40:00

标签: c++ boost-asio

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

  Worker ob1(&io_service);

  ob1.AsyncRead();
  io_service.run();

}

void Worker::AsyncRead() {
   socket.async_receive_from(buffer,endpoint, handler);
}

void handler (const boost::system::error_code& error, size_t bytes_received) {
   if(!error)
       handleData();
   AsyncRead();
}

现在,这很好用。但是,如果我使用boost :: Spawn()进行asyncRead()则会崩溃。

  void work(boost::asio::io_service* io_service) {

     auto ob1 = std::make_shared<Worker>(io_service);
  boost::asio::spawn(*io_service, [ob1](
                                      boost::asio::yield_context yield) {

      ob1->AsyncRead();

   });

  }

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

      io_service.run();

    }

崩溃的堆栈跟踪为:

PC: @           0x4e3502 boost::asio::basic_io_object<>::get_service()
*** SIGSEGV (@0x18) received by PID 25135 (TID 0x7f6bde13b7c0) from PID 24; stack trace: ***
    @     0x7f6bdd37d390 (unknown)
    @           0x4e3502 boost::asio::basic_io_object<>::get_service()
    @           0x4e3074 boost::asio::basic_datagram_socket<>::async_receive_from<>()

我想使其与boost::spawn()一起使用。我的spawn()返回后,work()将会怎样?

1 个答案:

答案 0 :(得分:1)

对于初学者来说,您的代码可能无法编译(handler必须是Worker的非静态成员函数,但这意味着它不满足async_receive_from的处理程序要求。

但是您询问的问题似乎更简单:

 auto ob1 = std::make_shared<Worker>(io_service);

创建共享指针

 boost::asio::spawn(*io_service, [ob1](
                                  boost::asio::yield_context yield) {

在服务上发布一个Coro,其中包含ob1的副本,因此它仍然有效。到目前为止一切顺利。

  ob1->AsyncRead();

这执行async_recieve_from,自然而然地返回,完成冠冕并释放ob1。但是async_receive_from仍在服务中待处理。

如果要在Coro中使用异步操作,则必须将yield_context作为完成令牌传递。你没有那样做。

您的代码从概念上应该看起来像:

  void work(boost::asio::io_service* io) {

  boost::asio::spawn(*io_service, [io](boost::asio::yield_context yield) {

       udp::socket socket(*io); 
       // ... more

       udp::endpoint ep;
       char buffer[1024];
       socket.async_receive_from(buffer, ep, yield); // throws on error

   });