2017-11-21 6 views
1

Der folgende Code verursacht SEGFAULT auf Clang-5.0 mit aktivierten Coroutinen-Unterstützung. Sie können den Code ausführen hier online: wandbox compiled codeBoost Asio-Timer in Coroutinen eingewickelt verursacht SEGFAULT auf clang-5.0

I Compiler-Optionen bin mit:

-stdlib=libc++ -fcoroutines-ts 

Als ich es unter GDB führen Sie es segfaults in async_await nach coro.resume(); wird genannt. Die Funktion "wait_resume" wird nie erreicht. Ich erwarte, dass dies ein Objektlebensdauerproblem ist. Sehr viel gleiches Stück Code kompiliert und läuft unter MSVC 2017 ohne Probleme.

Die Ausgabe des Programms ist:

i=0 
Segmentation fault 
Finish 

Quellcode:

#define BOOST_THREAD_PROVIDES_FUTURE 
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION // Enables future::then 
#include <boost/thread.hpp> 
#include <boost/asio.hpp> 
#include <boost/asio/system_timer.hpp> 

#include <experimental/coroutine> 
#include <chrono> 
#include <iostream> 

namespace std 
{ 
    namespace experimental 
    { 
     template <typename... Args> 
     struct coroutine_traits<boost::future<void>, Args...> { 
     struct promise_type { 
      boost::promise<void> p; 
      auto get_return_object() { return p.get_future(); } 
      std::experimental::suspend_never initial_suspend() { return {}; } 
      std::experimental::suspend_never final_suspend() { return {}; } 
      void unhandled_exception(){} 

      void return_void() { p.set_value(); } 
     }; 
     }; 
    } 
} 

namespace asioadapt 
{ 
    using namespace std::experimental; 

    template <typename R> auto operator co_await(boost::future<R> &&f) { 
     struct Awaiter { 
     boost::future<R> &&input; 
     boost::future<R> output; 
     bool await_ready() { return false; } 
     auto await_resume() { return output.get(); } 
     void await_suspend(std::experimental::coroutine_handle<> coro) { 
      input.then([this, coro](auto result_future) mutable{ 
       this->output = std::move(result_future); 
       coro.resume(); 
      }); 
     } 
     }; 
     return Awaiter{ static_cast<boost::future<R>&&>(f) }; 
    } 

    template <typename R, typename P> 
    auto async_await(boost::asio::system_timer &t, std::chrono::duration<R, P> d) { 
     struct Awaiter 
     { 
     boost::asio::system_timer &t; 
     std::chrono::duration<R, P> d; 
     boost::system::error_code ec; 

     bool await_ready() { return false; } 
     void await_suspend(std::experimental::coroutine_handle<> coro) { 
      t.expires_from_now(d); 
      t.async_wait([this, &coro](auto ec) mutable { 
       this->ec = ec; 
       coro.resume(); 
      }); 
     } 

     void await_resume() { 
      if (ec) 
       throw boost::system::system_error(ec); 
     } 
     }; 

     return Awaiter{ t, d }; 
    } 
} 

using namespace boost; 
using namespace boost::asio; 
using namespace std::chrono_literals; 
using namespace asioadapt; 

boost::future<void> sleepy(io_service &io, int &i) { 
    system_timer timer(io); 
    std::cout << "i=" << i << std::endl; 

    co_await async_await(timer, 100ms); 
    ++i; 
    std::cout << "i=" << i << std::endl; 

    co_await async_await(timer, 100ms); 
    ++i; 
    std::cout << "i=" << i << std::endl; 

    co_await async_await(timer, 100ms); 
    ++i; 
    std::cout << "i=" << i << std::endl; 
} 


void test(){ 
    int i = 0; 
    io_service io; 
    auto future = sleepy(io, i); 
    io.run(); 

    std::cout << "i=" << i << std::endl; 
} 


int main() 
{ 
test(); 
} 

Antwort

0

ich die & in Lambda-Capture await_suspend Funktion übersehen haben. So wird der coroutine_handle nach diesem Aufruf zerstört.