Следующий код вызывает SEGFAULT на clang-5.0 с включенной поддержкой сопрограмм.
Вы можете запустить код онлайн здесь:
скомпилированный код wandbox
Я использую параметры компилятора:
-stdlib=libc++ -fcoroutines-ts
Когда я запускаю его под GDB, это SEGFAULTs в async_await после coro.resume (); называется.
Функция 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();
}
Я упустил из виду & в лямбда-захвате функция await_suspend. Таким образом, дескриптор coroutine_handle уничтожается после этого вызова.
Других решений пока нет …