2017-04-14 50 views
0

我正在使用協程來玩asio,並想測試如何調用異步函數。我有以下代碼:想知道爲什麼我不能只捕獲協程的asio :: handler_type的引用

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; 
} 

這很奇怪,如果我把&處理程序捕獲列表中的執行流將被搞砸了,然後它擊中分段錯誤。但是,如果我使用「處理程序」而不是任何問題運行(然後我需要在lambda當然副本)。

搜索過,找不到任何相關的內容。預先感謝您的幫助。

回答

0

正如坦納非常漂亮解釋here

  • 雖然spawn() 增加了工作的io_service(處理程序將啓動,並跳轉到 協程),協程本身是不行的。爲了防止在協程未完成時結束事件循環, 可能需要在產生之前將工作添加到io_service

如果您在run()後添加一個額外的跡線:

io_service.run(); 
std::cout << "BYE" << std::endl; 

然後,運行幾次,直到你足夠幸運,不及早獲得SEGV,你可以看到輸出像以下內容:

hello 
enter 
done 
BYE 

實際上,io_service對象的回報,破壞待處理操作/處理程序,這也破壞了coro¹的堆疊上下文。展開該堆棧自毀住該堆棧上的(局部)變量:

  • 處理
  • 結果
  • 定時器

而且,由於timer沒有在完成處理程序捕獲async_wait,該定時器簡單地取消,但仍嘗試調用完成處理程序,該處理程序現在引用一個現已解散的堆棧變量handler

複製handler顯然²確保科羅活着。


要回答的核心問題「想測試一個異步功能如何可以被稱爲」我建議更簡單的成語:

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到協程範圍內,所以也許短耳內部鎖定了成shared_ptr,不太清楚這些實施細則自己

+0

謝謝你很多關於詳細的說明。我在ctor和dtor中放置了一個輸出的測試對象,顯然在定時器觸發之前有一個堆棧展開。 –

相關問題