#include <iostream>
#include <future>
#include <coroutine>
#include <string>
#include <iostream>
#include <future>
#include <coroutine>
#include <thread>
// 定义协程的返回类型
struct MyTask {
struct promise_type {
MyTask get_return_object() {
return {std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {
std::cerr << "Unhandled exception in coroutine\n";
std::terminate();
}
std::future<void> get_future() {
return result.get_future();
}
std::promise<void> result;
};
std::coroutine_handle<promise_type> coro;
~MyTask() {
if (coro) coro.destroy();
}
MyTask(const MyTask&) = delete;
MyTask& operator=(const MyTask&) = delete;
MyTask(MyTask&& other) noexcept
: coro(std::exchange(other.coro, {})) {}
MyTask& operator=(MyTask&& other) noexcept {
if (this != &other) {
coro = std::exchange(other.coro, {});
}
return *this;
}
void start() {
if (coro) coro.resume();
}
void wait()
{
if (coro) coro.promise().get_future().wait();
}
private:
MyTask(std::coroutine_handle<promise_type> h) : coro(h) {}
friend struct promise_type; // 允许 promise_type 访问私有构造函数
};
// 协程函数
MyTask myCoroutine() {
std::cout << "Coroutine started\n";
co_await std::suspend_always{}; // 协程的“暂停点”(实际不暂停)
std::cout << "Coroutine resumed\n";
}
int main() {
MyTask task = myCoroutine();
std::cout << "Launching coroutine...\n";
task.start(); // 启动协程
// 做一些其他事情...
std::this_thread::sleep_for(std::chrono::seconds(1));
task.wait(); // 等待协程完成
std::cout << "Coroutine completed\n";
return 0;
}
-
#include <coroutine> #include <iostream> #include <stdexcept> #include <thread> struct awaitable { std::thread* p_out; bool await_ready() { printf("ready\n"); return false; } void await_suspend(std::coroutine_handle<> h) // 这个是协程挂起时,要执行的操作 { std::thread& out = *p_out; if (out.joinable()) throw std::runtime_error("thread 输出参数非空"); out = std::thread([h] { sleep(5); printf("开始执行唤醒%ld\n", std::this_thread::get_id()); h.resume(); // !!这里其实就是恢复协程,执行co_await switch_to_new_thread下面的代码 sleep(2); printf("异步线程退出\n"); }); printf("新线程id:%ld 当前线程id:%ld\n", out.get_id(), std::this_thread::get_id()); std::cout << "2新线程 ID:" << out.get_id() << '\n'; } void await_resume() { printf("await_resume\n"); } }; awaitable switch_to_new_thread(std::thread& out) { printf("切换线程\n"); return awaitable{&out}; } struct task { struct promise_type { int value; promise_type() { printf("promise_type构造函数\n"); } task get_return_object() { printf("get_return_object\n"); return { std::coroutine_handle<promise_type>::from_promise(*this) }; } std::suspend_never initial_suspend() { printf("initial_suspend\n"); return {}; } std::suspend_never final_suspend() noexcept { printf("final_suspend\n"); return {}; } void return_value(int v) { printf("return_value: %d\n", v); value = v; } void unhandled_exception() { printf("unhandled_exception\n"); } }; std::coroutine_handle<promise_type> coro_handle; task(std::coroutine_handle<promise_type> h) : coro_handle(h) {} ~task() { coro_handle.destroy(); } int get() { return coro_handle.promise().value; } }; task resuming_on_new_thread(std::thread& out) { printf("进入到了resuming_on_new_thread\n"); std::cout << "协程开始,线程 ID:" << std::this_thread::get_id() << '\n'; co_await switch_to_new_thread(out); std::cout << "协程恢复,线程 ID:" << std::this_thread::get_id() << '\n'; co_return 42; // 返回一个值 } // 协程函数,使用 co_return 返回一个整数值 task example_coroutine() { co_return 123; // 返回一个整数值 } int main() { // std::thread out; // auto t = resuming_on_new_thread(out); // std::cout << "!!这里是同步立马执行,协程只会恢复到resuming_on_new_thread函数" << std::this_thread::get_id() << '\n'; // out.join(); // 等待新线程完成 // std::cout << "协程返回的值是:" << t.get() << '\n'; auto t = example_coroutine(); std::cout << "协程返回的值是:" << t.get() << '\n'; }
- co_await 表达式——用于暂停执行,直到恢复:
co_await
后面通常跟随一个可等待对象(awaitable),这个对象必须符合特定的条件,使得编译器能够正确地生成协程相关的代码
这个对象必须实现以下三个函数或者函数模板:
-
await_suspend:用于控制协程的暂停和恢复,通常是一个异步操作。
-
await_resume:用于获取
co_await
表达式的结果或者执行特定的操作。 -
await_ready(可选):用于确定
co_await
表达式是否可以立即执行,通常返回一个bool
值。
co_await std::suspend_always{}
属于一种特殊情况,用于在协程中立即暂停执行,并且没有实际的异步操作。这是 C++ 标准库中提供的一种符合 awaitable
概念的对象。std::suspend_always
会始终导致协程暂停,因为其 await_suspend
方法会返回一个总是暂停的状态。
下面是await 和resum的一个简单例子
#include <coroutine>
#include <iostream>
#include <stdexcept>
#include <thread>
struct awaitable
{
std::thread* p_out;
bool await_ready()
{
printf("ready\n");
return false;
}
void await_suspend(std::coroutine_handle<> h) // 这个是协程挂起时,要执行的操作
{
std::thread& out = *p_out;
if (out.joinable())
throw std::runtime_error("thread 输出参数非空");
out = std::thread([h]
{
sleep(5);
printf("开始执行唤醒%ld\n", std::this_thread::get_id());
h.resume(); // !!这里其实就是恢复协程,执行co_await switch_to_new_thread下面的代码
sleep(2);
printf("异步线程退出\n");
});
printf("新线程id:%ld 当前线程id:%ld\n", out.get_id(), std::this_thread::get_id());
std::cout << "2新线程 ID:" << out.get_id() << '\n';
}
void await_resume()
{
printf("await_resume\n");
}
};
awaitable switch_to_new_thread(std::thread& out)
{
printf("切换线程\n");
return awaitable{&out};
}
struct task
{
struct promise_type
{
promise_type()
{
printf("promise_type构造函数\n");
}
task get_return_object()
{
printf("get_return_object\n");
return {};
}
std::suspend_never initial_suspend()
{
printf("initial_suspend\n");
return {};
}
std::suspend_never final_suspend() noexcept
{
printf("final_suspend\n");
return {};
}
void return_void()
{
printf("return_void\n");
}
void unhandled_exception()
{
printf("unhandled_exception\n");
}
};
};
task resuming_on_new_thread(std::thread& out)
{
printf("进入到了resuming_on_new_thread\n");
std::cout << "协程开始,线程 ID:" << std::this_thread::get_id() << '\n';
co_await switch_to_new_thread(out);
std::cout << "协程恢复,线程 ID:" << std::this_thread::get_id() << '\n';
}
int main()
{
std::thread out;
resuming_on_new_thread(out);
std::cout << "!!这里是同步立马执行,协程只会恢复到resuming_on_new_thread函数" << std::this_thread::get_id() << '\n';
out.join(); // 等待新线程完成
}
suspend_never 指示编译器永远不要挂起协程,在 co_await
处立即继续执行。
suspend_always: 指示编译器总是挂起协程,在 co_await 处暂停协程执行,等待后续的异步操作完成后再恢复执行。
- co_yield 表达式——用于暂停执行并返回一个值:
- co_return 语句——用于完成执行并返回一个值:
#include <coroutine> #include <iostream> #include <stdexcept> #include <thread> #include <coroutine> #include <iostream> #include <vector> // 定义 generator 类型,用于协程逐步生成值 struct generator { struct promise_type { int value; std::coroutine_handle<> continuation; generator get_return_object() { return { std::coroutine_handle<promise_type>::from_promise(*this) }; } std::suspend_always initial_suspend() { continuation = std::coroutine_handle<promise_type>::from_promise(*this); return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() { } void unhandled_exception() { std::terminate(); } auto yield_value(int v) { value = v; // continuation.resume(); return std::suspend_always{}; } }; std::coroutine_handle<promise_type> coro_handle; generator(std::coroutine_handle<promise_type> h) : coro_handle(h) {} ~generator() { coro_handle.destroy(); } bool next() { if (coro_handle) { coro_handle.resume(); return !coro_handle.done(); } return false; } int current_value() const { return coro_handle.promise().value; } }; generator example_generator() { for (int i = 0; i < 5; ++i) { co_yield i; // 逐个生成值 } } int main() { auto gen = example_generator(); while (gen.next()) { std::cout << "生成的值是:" << gen.current_value() << '\n'; } return 0; }
#include <coroutine>
#include <cstdint>
#include <exception>
#include <iostream>
template<typename T>
struct Generator
{
// 类名 'Generator' 只是我们的选择,使用协程魔法不依赖它。
// 编译器通过关键词 'co_yield' 的存在识别协程。
// 你可以使用 'MyGenerator'(或者任何别的名字)作为替代,只要在类中包括了
// 拥有 'MyGenerator get_return_object()' 方法的嵌套 struct promise_type。
// (注意:在重命名时,你还需要调整构造函数/析构函数的声明。)
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type // 必要
{
T value_;
std::exception_ptr exception_;
Generator get_return_object()
{
return Generator(handle_type::from_promise(*this));
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void unhandled_exception() { exception_ = std::current_exception(); } // 保存异常
template<typename From>
std::suspend_always yield_value(From&& from)
{
value_ = std::forward<From>(from); // 在承诺中缓存结果
return {};
}
void return_void() {}
};
handle_type h_;
Generator(handle_type h) : h_(h) {}
~Generator() { h_.destroy(); }
explicit operator bool()
{
fill(); // 获知协程是结束了还是仍能通过 C++ getter(下文的 operator())
// 获得下一个生成值的唯一可靠方式,是执行/恢复协程到下一个 co_yield 节点
// (或让执行流抵达结尾)。
// 我们在承诺中存储/缓存了执行结果,使得 getter(下文的 operator())
// 可以获得这一结果而不执行协程。
return !h_.done();
}
T operator()()
{
fill();
full_ = false;// 我们将移动走先前缓存的结果来重新置空承诺
return std::move(h_.promise().value_);
}
private:
bool full_ = false;
void fill()
{
if (!full_)
{
h_();
if (h_.promise().exception_)
std::rethrow_exception(h_.promise().exception_);
// 在调用上下文中传播协程异常
full_ = true;
}
}
};
Generator<uint64_t>
fibonacci_sequence(unsigned n)
{
if (n == 0)
co_return;
if (n > 94)
throw std::runtime_error("斐波那契序列过大,元素将会溢出。");
co_yield 0;
if (n == 1)
co_return;
co_yield 1;
if (n == 2)
co_return;
uint64_t a = 0;
uint64_t b = 1;
for (unsigned i = 2; i < n; i++)
{
uint64_t s = a + b;
co_yield s;
a = b;
b = s;
}
}
int main()
{
try
{
auto gen = fibonacci_sequence(10); // 最大值94,避免 uint64_t 溢出
for (int j = 0; gen; j++)
std::cout << "fib(" << j << ")=" << gen() << '\n';
}
catch (const std::exception& ex)
{
std::cerr << "发生了异常:" << ex.what() << '\n';
}
catch (...)
{
std::cerr << "未知异常。\n";
}
}
set(CMAKE_CXX_FLAGS "-std=c++20 -fcoroutines")