协程是C++20引入的一项重要特性,它允许函数的执行被暂停并在之后恢复,非常适合用于异步编程、数据生产者/消费者模式、状态机等场景。协程的引入旨在提供一种更简洁和直观的方式来处理异步操作和非阻塞编程。以下是C++协程的关键概念和使用示例:
1. 协程基础
在C++中,协程是通过特殊的函数实现的,这些函数可以使用co_await
、co_return
和co_yield
关键字来暂停和恢复执行。
cpp
#include <coroutine>
#include <iostream>
#include <future>
std::future<void> simpleCoroutine() {
std::cout << "Hello, ";
co_await std::suspend_always{};
std::cout << "World!" << std::endl;
co_return;
}
void runSimpleCoroutine() {
auto future = simpleCoroutine();
future.get(); // 输出:Hello, World!
}
2. 使用co_yield
生成值
协程可以使用co_yield
生成一系列值,非常适合实现生成器模式。
cpp
#include <coroutine>
#include <iostream>
#include <vector>
struct Generator {
struct promise_type {
int current_value;
std::suspend_always yield_value(int value) {
current_value = value;
return {};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
Generator get_return_object() { return Generator{this}; }
void return_void() {}
void unhandled_exception() { std::exit(1); }
};
std::coroutine_handle<promise_type> coro;
Generator(promise_type* p) : coro(std::coroutine_handle<promise_type>::from_promise(*p)) {}
~Generator() { if (coro) coro.destroy(); }
int getValue() { return coro.promise().current_value; }
bool next() { coro.resume(); return !coro.done(); }
};
Generator generateNumbers() {
for (int i = 0; i < 5; ++i) {
co_yield i;
}
}
void runGenerateNumbers() {
auto gen = generateNumbers();
while (gen.next()) {
std::cout << gen.getValue() << " ";
}
// 输出:0 1 2 3 4
}
3. 使用co_await
等待异步操作
co_await
表达式可以暂停当前协程的执行,直到等待的对象准备就绪。
cpp
#include <coroutine>
#include <future>
#include <iostream>
std::future<int> asyncComputation() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return std::async(std::launch::async, []() { return 42; });
}
std::future<void> awaitCoroutine() {
int result = co_await asyncComputation();
std::cout << "Result: " << result << std::endl;
co_return;
}
void runAwaitCoroutine() {
auto future = awaitCoroutine();
future.get(); // 输出:Result: 42
}
4. 协程与异常处理
协程支持异常处理,你可以在协程内部使用try
/catch
块来处理异常。
cpp
#include <coroutine>
#include <iostream>
#include <stdexcept>
std::future<void> exceptionCoroutine() {
try {
throw std::runtime_error("Example exception");
co_return;
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
}
void runExceptionCoroutine() {
auto future = exceptionCoroutine();
future.get(); // 输出:Caught exception: Example exception
}
通过这些示例可以看到C++协程如何用于不同的场景,它们提供了一种更直观和简洁的方式来处理异步操作、生成数据和编写复杂的控制流逻辑。