在协同程序中包含的提升asio计时器会导致clang-5.0上的SEGFAULT

时间:2017-11-21 07:28:13

标签: c++ boost clang asio c++-coroutine

以下代码导致clang-5.0上的SEGFAULT启用了协同程序支持。 您可以在此处在线运行代码: wandbox compiled code

我正在使用编译器选项:

-stdlib=libc++ -fcoroutines-ts

当我在GDB下运行它时,它在coro.resume()之后的async_await中的SEGFAULTs;叫做。 永远不会达到await_resume函数。 我希望这是一个对象生命周期问题。非常相同的代码片段在MSVC 2017下编译和运行,没有任何问题。

该计划的输出是:

i=0
Segmentation fault
Finish

源代码:

#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();
}

1 个答案:

答案 0 :(得分:0)

我忽视了&amp;在lambda中捕获await_suspend函数。因此,在此次调用后,coroutine_handle将被销毁。