C++20协程文档:gh_mirrors/st/STL中的协程使用指南

【免费下载链接】STL MSVC's implementation of the C++ Standard Library. 【免费下载链接】STL 项目地址: https://gitcode.com/gh_mirrors/st/STL

什么是C++20协程

C++20引入了协程(Coroutine)这一重要特性,它允许函数在执行过程中暂停并在稍后恢复,极大地简化了异步编程和生成器模式的实现。在gh_mirrors/st/STL项目中,协程的实现主要集中在stl/inc/coroutine头文件中。

协程与普通函数的主要区别在于它可以包含co_awaitco_yieldco_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一致性。

测试用例

项目中提供了丰富的协程测试用例,主要位于以下文件中:

这些测试用例展示了协程的各种用法,是学习和使用协程的良好参考。

总结

C++20协程为异步编程和生成器模式提供了强大的支持,gh_mirrors/st/STL项目中的协程实现遵循了C++标准,并提供了完整的功能。通过本文档,您应该对如何在该项目中使用协程有了基本的了解。

要深入学习协程,建议参考:

  • stl/inc/coroutine头文件的实现
  • 项目中的测试用例
  • C++20协程相关的标准文档

希望本文档能帮助您更好地理解和使用C++20协程!

【免费下载链接】STL MSVC's implementation of the C++ Standard Library. 【免费下载链接】STL 项目地址: https://gitcode.com/gh_mirrors/st/STL

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐