Как использовать Handler и boost :: asio :: async_result - PullRequest
1 голос
/ 29 апреля 2019

Как использовать 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;
}

Я ожидаю: return result.get ();даст волокно, а значение 2 получит.но код завершается с помощью: (прерывается сигналом 11: SIGSEGV), потому что handler.ec имеет значение null.

1 Ответ

1 голос
/ 29 апреля 2019

Этим

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

вы создаете лямбду, которая ставится в очередь в io_service.Это закрытие выполняется внутри io_service::run.Вы захватываете ссылку handler, которая является локальной внутри AsyncRead.Когда handler(2) вызывается

AsyncRead(&s,yield[er]);

сопрограмма возобновляется в вышеприведенной строке, result.get() вызывается из AsyncRead, AsyncRead заканчивается, и обработчик как локальная переменная уничтожается, но замыкание, которое выполняется в io_service::run по-прежнему ссылается на эту переменную - неопределенное поведение.

Вам нужно захватить обработчик по значению, переместив его в поток и лямбду:

  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;
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...