C++20 协程,await_resume return 左值,分段错误
C++20 Coroutines, await_resume return lvalue, Segmentation fault
正在发生
我想存储只移动数据到promise_type
,并在协程中获取它。我尝试 return return 来自 await_resume()
的左值。结果是编译成功但是执行时出现Segmentation fault
我该如何改进?
环境
- OS: WSL2 Ubuntu 20.04
- 编译器:gcc 10.3
- 命令:g++ -std=c++20 -fcoroutines main.cpp
代码
main.cpp:
#include <iostream>
#include <coroutine>
#include <memory>
struct task
{
struct promise_type
{
using data_type = std::unique_ptr<int>;
task get_return_object() noexcept
{
return task(std::coroutine_handle<promise_type>::from_promise(*this));
}
std::suspend_never initial_suspend() const noexcept { return {}; }
void unhandled_exception() {}
std::suspend_always final_suspend() const noexcept { return {}; }
data_type data; // my data
};
void set_data(promise_type::data_type&& data) // [2] set my data
{
handle.promise().data = std::forward<promise_type::data_type>(data);
}
void resume()
{
handle.resume();
}
task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
private:
std::coroutine_handle<promise_type> handle;
};
struct awaitalbe
{
bool await_ready() { return true; }
void await_suspend(std::coroutine_handle<task::promise_type> handle) { this->handle = handle; }
task::promise_type::data_type&& await_resume()
{
return std::move(handle.promise().data); // [3] get my data
}
std::coroutine_handle<task::promise_type> handle;
};
task f()
{
auto p2 = co_await awaitalbe{}; // [4] Segmentation fault here. after [3]
std::cout << (*p2) << std::endl;
}
int main(int argc, char* argv[])
{
auto task1 = f();
task::promise_type::data_type p1 = std::make_unique<task::promise_type::data_type::element_type>(10);
task1.set_data(std::move(p1)); // [1] set my data
task1.resume();
return 0;
}
在你的 struct awaitable
中,你有:
bool await_ready() { return true; }
澄清一下,await_ready
是一种机制,用于确定与可等待对象对应的结果是否就绪。如果准备就绪,那么真的没有充分的理由暂停调用协程(即 co_await
可等待的协程)并等待结果 - 只需调用 await_resume
即可检索结果。
它允许您执行以下操作:
bool await_ready() {
if (will_read_block()) {
return false;
}
read_some_data_from_file();
return true;
}
这样非阻塞读取将同步完成。
在你的情况下,你总是 return 正确。这告诉运行时:当协程等待 awaitable
时,永远不要暂停该协程并直接调用 await_resume
,跳过暂停和 await_suspend
。实际上,如果您在 await_suspend
中设置断点(或者如果您的调试器不喜欢协同程序,则使用打印语句)在 await_suspend
中,您会发现它永远不会被调用。因此,您实际上从未将任何东西分配给 awaitable
结构中的 handle
成员,当您试图从中获得承诺时会导致未定义的行为。
解决方案:只需 return false
来自 await_ready
.
正在发生
我想存储只移动数据到promise_type
,并在协程中获取它。我尝试 return return 来自 await_resume()
的左值。结果是编译成功但是执行时出现Segmentation fault
我该如何改进?
环境
- OS: WSL2 Ubuntu 20.04
- 编译器:gcc 10.3
- 命令:g++ -std=c++20 -fcoroutines main.cpp
代码
main.cpp:
#include <iostream>
#include <coroutine>
#include <memory>
struct task
{
struct promise_type
{
using data_type = std::unique_ptr<int>;
task get_return_object() noexcept
{
return task(std::coroutine_handle<promise_type>::from_promise(*this));
}
std::suspend_never initial_suspend() const noexcept { return {}; }
void unhandled_exception() {}
std::suspend_always final_suspend() const noexcept { return {}; }
data_type data; // my data
};
void set_data(promise_type::data_type&& data) // [2] set my data
{
handle.promise().data = std::forward<promise_type::data_type>(data);
}
void resume()
{
handle.resume();
}
task(std::coroutine_handle<promise_type> handle) : handle(handle) {}
private:
std::coroutine_handle<promise_type> handle;
};
struct awaitalbe
{
bool await_ready() { return true; }
void await_suspend(std::coroutine_handle<task::promise_type> handle) { this->handle = handle; }
task::promise_type::data_type&& await_resume()
{
return std::move(handle.promise().data); // [3] get my data
}
std::coroutine_handle<task::promise_type> handle;
};
task f()
{
auto p2 = co_await awaitalbe{}; // [4] Segmentation fault here. after [3]
std::cout << (*p2) << std::endl;
}
int main(int argc, char* argv[])
{
auto task1 = f();
task::promise_type::data_type p1 = std::make_unique<task::promise_type::data_type::element_type>(10);
task1.set_data(std::move(p1)); // [1] set my data
task1.resume();
return 0;
}
在你的 struct awaitable
中,你有:
bool await_ready() { return true; }
澄清一下,await_ready
是一种机制,用于确定与可等待对象对应的结果是否就绪。如果准备就绪,那么真的没有充分的理由暂停调用协程(即 co_await
可等待的协程)并等待结果 - 只需调用 await_resume
即可检索结果。
它允许您执行以下操作:
bool await_ready() {
if (will_read_block()) {
return false;
}
read_some_data_from_file();
return true;
}
这样非阻塞读取将同步完成。
在你的情况下,你总是 return 正确。这告诉运行时:当协程等待 awaitable
时,永远不要暂停该协程并直接调用 await_resume
,跳过暂停和 await_suspend
。实际上,如果您在 await_suspend
中设置断点(或者如果您的调试器不喜欢协同程序,则使用打印语句)在 await_suspend
中,您会发现它永远不会被调用。因此,您实际上从未将任何东西分配给 awaitable
结构中的 handle
成员,当您试图从中获得承诺时会导致未定义的行为。
解决方案:只需 return false
来自 await_ready
.