struct Task {
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type {
auto get_return_object() {
return Task{handle_type::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() { }
void unhandled_exception() {}
};
handle_type handle;
Task(handle_type h) : handle(h) {}
~Task() {
if (handle) handle.destroy();
}
Task(const Task&) = delete;
Task& operator=(const Task&) = delete;
Task(Task&& other) : handle(other.handle) { other.handle = nullptr; }
Task& operator=(Task&& other) {
if (this != &other) {
if (handle) handle.destroy();
handle = other.handle;
other.handle = nullptr;
}
return *this;
}
bool done() const { return handle.done(); }
void resume() { handle.resume(); }
};
Task process_queue_item(int i) {
if (!atomicQueue[i].valid) {
co_await std::suspend_always{};
}
atomicQueue[i].res = remote1(atomicQueue[i].i, atomicQueue[i].a, atomicQueue[i].b);
}
why line atomicQueue[i].res = ... cause segfault?
Coroutine lifetime issues: If the coroutine is resumed after the atomicQueue or its elements have been destroyed, this would lead to accessing invalid memory.
solusion
Task process_queue_item(int i) {
if (i < 0 || i >= atomicQueue.size()) {
// Handle index out of bounds
co_return;
}
if (!atomicQueue[i].valid) {
co_await std::suspend_always{};
}
// Additional check after resuming
if (!atomicQueue[i].valid) {
// Handle unexpected invalid state
co_return;
}
try {
atomicQueue[i].res = remote1(atomicQueue[i].i, atomicQueue[i].a, atomicQueue[i].b);
} catch (const std::exception& e) {
// Handle any exceptions from remote1
// Log error, set error state, etc.
}
}