Coroutines in C++ are a powerful tool for writing asynchronous code. However, managing their lifecycle, especially when needing to cancel them or handle timeouts, requires careful design. In this example, we will see how to create a coroutine with cancellation support and implement timeout functionality using C++20 coroutines.
#include <iostream>
#include <coroutine>
#include <thread>
#include <atomic>
#include <chrono>
struct CancelableTask {
struct promise_type {
CancelableTask get_return_object() {
return {}; // Returning a CancelableTask instance
}
std::suspend_never initial_suspend() {
return {};
}
std::suspend_always final_suspend() noexcept {
return {};
}
void unhandled_exception() {
std::terminate();
}
void return_void() {}
};
std::atomic canceled{false};
void cancel() {
canceled = true;
}
bool is_canceled() const {
return canceled;
}
};
CancelableTask sleep_for(int seconds) {
for (int i = 0; i < seconds; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Slept for " << (i + 1) << " seconds" << std::endl;
if (canceled) {
std::cout << "Cancelled!" << std::endl;
co_return; // Exiting the coroutine
}
}
co_return; // Normal exit
}
int main() {
CancelableTask task;
auto coroutine = sleep_for(5); // Execute sleep_for coroutine
std::this_thread::sleep_for(std::chrono::seconds(2)); // Wait for 2 seconds
task.cancel(); // Cancel the coroutine
std::this_thread::join(); // Wait for the coroutine to finish
return 0;
}
How do I avoid rehashing overhead with std::set in multithreaded code?
How do I find elements with custom comparators with std::set for embedded targets?
How do I erase elements while iterating with std::set for embedded targets?
How do I provide stable iteration order with std::unordered_map for large datasets?
How do I reserve capacity ahead of time with std::unordered_map for large datasets?
How do I erase elements while iterating with std::unordered_map in multithreaded code?
How do I provide stable iteration order with std::map for embedded targets?
How do I provide stable iteration order with std::map in multithreaded code?
How do I avoid rehashing overhead with std::map in performance-sensitive code?
How do I merge two containers efficiently with std::map for embedded targets?