struct任务是从https://github.com/Quuxplusone/coro/blob/master/include/coro/gor_task.h修改的。我只是将suspend_always
in Line 18更改为suspend_never。
// test.cpp
#include <exception>
#include <experimental/coroutine>
#include <variant>
template<class T>
struct task {
struct promise_type {
std::variant<std::monostate, T, std::exception_ptr> result_;
std::experimental::coroutine_handle<void> waiter_;
task get_return_object() { return task(this); }
auto initial_suspend() { return std::experimental::suspend_never{}; } // Originally suspend_always
auto final_suspend() {
struct Awaiter {
promise_type *me_;
bool await_ready() { return false; }
void await_suspend(std::experimental::coroutine_handle<void> caller) {
me_->waiter_.resume();
}
void await_resume() {}
};
return Awaiter{this};
}
template<class U>
void return_value(U&& u) {
result_.template emplace<1>(static_cast<U&&>(u));
}
void unhandled_exception() {
result_.template emplace<2>(std::current_exception());
}
};
bool await_ready() { return false; }
void await_suspend(std::experimental::coroutine_handle<void> caller) {
coro_.promise().waiter_ = caller;
coro_.resume();
}
T await_resume() {
if (coro_.promise().result_.index() == 2) {
std::rethrow_exception(std::get<2>(coro_.promise().result_));
}
return std::get<1>(coro_.promise().result_);
}
~task() {
coro_.destroy();
}
private:
using handle_t = std::experimental::coroutine_handle<promise_type>;
task(promise_type *p) : coro_(handle_t::from_promise(*p)) {}
handle_t coro_;
};
#include <stdio.h>
task<int> f2() {
puts("enter f2");
co_return 1;
}
task<int> f1() {
puts("enter f1");
int a = co_await f2();
printf("f2 return: %d\n", a);
co_return a;
}
int main() {
f1();
}
$ clang++ -fcoroutines-ts -std=c++17 -stdlib=libc++ -lc++ -lc++abi test.cpp -o test
$ ./test
enter f1
enter f2
fish: './test' terminated by signal SIGSEGV (Address boundary error)
由于没有co_await
,我希望可以打印f2 return: 1
,并且程序应该正常退出,但是由于segfault而崩溃。为什么以及如何解决此问题?
当协程函数执行co_await
时,它将暂停该函数的执行,并将该执行的恢复安排给其他人。此“其他人”最终取决于co_await
被使用的表达式,协程函数的promise类型以及协程返回的未来类型。
所以让我们在这里看看控制流。
f2
被调用。它执行,然后通过co_return
终止。这意味着f2
的协程句柄为complete。这也意味着将调用promise类型的final_suspend
。好吧,协程机器希望final_suspend
将返回您的task::promise
提供的等待类型。
除外... task::promise::waiter_
未初始化。这是因为仅await_suspend
为waiter_
分配了一个值。并且还没有人将co_await
的返回值设置为f2
。因此,在此之前,waiter_
没有值。
因此,在调用f2
的那一刻,您尝试继续执行最高为nullptr
的协程句柄,从而导致崩溃。
如果首先检查final_suspend
的Awaiter
类型以查看waiter_
是否为nullptr
(这意味着尚无人在等待协程)会更有意义,如果是,则从[ C0]。