I have implemented my own experimental coroutine awaiter object to grasp the awaiter rationale. I call a coroutine which is foo in my example. In await_suspend method, I invoked a thread and this thread executes a job thus at the end of the job it will resume the awaiter.
However even if I control the life cycle of the tread with unique_ptr and control the joinable in the awaiter destructure, somehow handle.resume generates segfault.
Last but not least, when I use jthread instead of thread it works fine. I could not figure out what was missing here.
#include <coroutine>
#include <iostream>
#include <thread>
struct ReturnObject {
struct promise_type {
ReturnObject get_return_object() {
auto handle = std::coroutine_handle<promise_type>::from_promise(*this);
return ReturnObject{handle};
}
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() {
}
// void return_void() noexcept {
// }
void return_value(int val) noexcept {
this->value = val;
}
std::suspend_always yield_value(int val) {
this->value = val;
return std::suspend_always{};
}
double get_value() const noexcept { return value; }
void set_value(double val) noexcept { value = val; }
private:
double value{3.14};
};
std::coroutine_handle<promise_type> h_;
ReturnObject(std::coroutine_handle<promise_type> h) : h_{h} {
}
operator std::coroutine_handle<promise_type>() { return h_; }
int get_value() const {
return h_.promise().get_value();
}
~ReturnObject() {
h_.destroy();
}
};
void do_work(std::coroutine_handle<ReturnObject::promise_type>& h) {
std::cout << "do_work\n";
h.resume();
}
struct SuspendAlways {
void await_suspend(std::coroutine_handle<ReturnObject::promise_type> h) {
std::cout << "await suspend\n";
th = std::make_unique<std::thread>(do_work, std::ref(h)); //(1)
//std::jthread (&SuspendAlways::do_work, this, std::ref(h)); //(2)
}
void await_resume() {
std::cout << "await_resume\n";
}
bool await_ready() const noexcept { return false; }
~SuspendAlways() {
std::cout << "~SuspendAlways\n";
if (th->joinable()) th->join();//(1)
}
std::unique_ptr< std::thread> th;//(1)
};
ReturnObject foo() {
std::cout << "1. Hello World!\n";
co_await SuspendAlways{};
std::cout << "2. Hello World!\n";
}
int main(int argc, char **argv) {
auto ret = foo();
using namespace std::chrono_literals;
std::this_thread::sleep_for(5000ms);
std::cout << std::boolalpha << ret.h_.done() << std::endl;
}