C++20协程文档:gh_mirrors/st/STL中的协程使用指南
C++20协程文档:gh_mirrors/st/STL中的协程使用指南
什么是C++20协程
C++20引入了协程(Coroutine)这一重要特性,它允许函数在执行过程中暂停并在稍后恢复,极大地简化了异步编程和生成器模式的实现。在gh_mirrors/st/STL项目中,协程的实现主要集中在stl/inc/coroutine头文件中。
协程与普通函数的主要区别在于它可以包含co_await、co_yield和co_return关键字,这些关键字使得函数能够在特定点暂停执行,并将控制权交还给调用者,同时保留当前的执行状态。
协程的基本组件
coroutine_handle
coroutine_handle是协程的核心组件之一,它表示一个协程的句柄,用于控制协程的执行。在stl/inc/coroutine中定义了两种coroutine_handle特化版本:
coroutine_handle<void>:不关联任何Promise对象的协程句柄coroutine_handle<_CoroPromise>:关联特定Promise类型的协程句柄
// 从地址创建协程句柄
static constexpr coroutine_handle from_address(void* const _Addr) noexcept;
// 恢复协程执行
void resume() const;
// 销毁协程
void destroy() const noexcept;
// 检查协程是否已完成
bool done() const noexcept;
Promise类型
每个协程都必须关联一个Promise类型,它负责协程的状态管理和结果传递。Promise类型需要定义一系列成员函数,如get_return_object()、initial_suspend()、final_suspend()等。
在stl/inc/coroutine中,定义了coroutine_traits模板,用于获取协程的Promise类型:
template <class _Ret, class...>
struct coroutine_traits : _Coroutine_traits<_Ret> {};
挂起类型
协程提供了两种基本的挂起类型:
suspend_never:从不挂起suspend_always:总是挂起
struct suspend_never {
constexpr bool await_ready() const noexcept { return true; }
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
struct suspend_always {
constexpr bool await_ready() const noexcept { return false; }
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
协程关键字
co_return
co_return用于从协程返回一个值并结束协程。
示例:
// 来自tests/std/tests/P0912R5_coroutine/test.cpp
task<int> triangular_number(int n) {
if (n <= 0)
co_return 0;
co_return n + co_await triangular_number(n - 1);
}
co_await
co_await用于暂停协程,等待某个异步操作完成。
示例:
// 来自tests/std/tests/VSO_0971246_legacy_await_headers/test.cpp
task<int> test_await() {
co_await f0();
auto& imm = co_await fimm();
co_return imm.val;
}
co_yield
co_yield用于从协程生成一个值,同时暂停协程,允许后续恢复执行。
示例:
// 来自tests/std/tests/P2502R2_generator/test.cpp
generator<int> count_up_to(int max) {
for (int i = 0; i <= max; ++i)
co_yield i;
}
协程的实际应用
生成器模式
生成器是协程的一个常见应用,它可以生成一系列值,而无需一次性创建所有值。在测试代码tests/std/tests/P2502R2_generator/test.cpp中,展示了如何使用协程实现生成器:
generator<int> iota(int start) {
while (true)
co_yield start++;
}
generator<pair<int, int>> zip(generator<int> a, generator<int> b) {
for (auto [it1, it2] = tuple{a.begin(), b.begin()}; it1 != a.end() && it2 != b.end(); ++it1, ++it2)
co_yield {*it1, *it2};
}
异步操作
协程非常适合异步操作,如tests/std/tests/P0912R5_coroutine/test.cpp中的例子所示:
task<int> triangular_number(int n) {
if (n <= 0)
co_return 0;
co_return n + co_await triangular_number(n - 1);
}
这个例子使用协程实现了一个计算三角形数的异步函数,它通过co_await递归地等待子任务完成。
范围生成
协程还可以与范围库结合使用,生成一系列值:
// 来自tests/std/tests/P2502R2_generator/test.cpp
generator<int> generate_nested(int hi, int depth) {
if (depth <= 0) {
co_yield hi;
return;
}
co_yield ranges::elements_of(iota_repeater(hi, depth - 1));
co_yield ranges::elements_of(iota_repeater(hi, depth - 1));
co_yield hi;
co_yield ranges::elements_of(co_upto<int>(hi));
}
编译和使用协程
要在gh_mirrors/st/STL中使用协程,需要确保编译器支持C++20或更高版本。在项目的CMake配置中,可以通过设置适当的编译选项来启用协程支持。
此外,需要注意协程的ABI兼容性。在stl/inc/coroutine中定义了:
#ifndef _ALLOW_COROUTINE_ABI_MISMATCH
#pragma detect_mismatch("_COROUTINE_ABI", "2")
#endif // !defined(_ALLOW_COROUTINE_ABI_MISMATCH)
这确保了协程相关代码的ABI一致性。
测试用例
项目中提供了丰富的协程测试用例,主要位于以下文件中:
- tests/std/tests/P0912R5_coroutine/test.cpp:测试协程的基本功能
- tests/std/tests/P2502R2_generator/test.cpp:测试生成器功能
- tests/std/tests/P2502R2_generator_iterator/test.cpp:测试生成器迭代器
- tests/std/tests/VSO_0971246_legacy_await_headers/test.cpp:测试遗留的await头文件
这些测试用例展示了协程的各种用法,是学习和使用协程的良好参考。
总结
C++20协程为异步编程和生成器模式提供了强大的支持,gh_mirrors/st/STL项目中的协程实现遵循了C++标准,并提供了完整的功能。通过本文档,您应该对如何在该项目中使用协程有了基本的了解。
要深入学习协程,建议参考:
- stl/inc/coroutine头文件的实现
- 项目中的测试用例
- C++20协程相关的标准文档
希望本文档能帮助您更好地理解和使用C++20协程!
更多推荐

所有评论(0)