C++ 协程

2024年8月28日 | 阅读 7 分钟

本文将讨论 协程、其用途、实现、示例输出

什么是协程?

C++ 中的 协程 是一种控制结构,其中 控制流 在不同例程之间传递而不停止。C++20 版本引入了 C++ 协程特性。协程是一种可以停止执行并在稍后恢复的方法。协程在开发的不同阶段以类似于一组有效的顺序代码的方式使用,但具有 非并发执行 的特性。由于 C++ 协程 具有无堆栈行为,因此该函数会将结果返回给 调用者。它继续指定的协程,该协程再次存储在已声明的隔离区域或堆栈中。

为什么使用 C++ 协程?

您可以逐行读取记录,这 没问题,或者您可以读取一些关键且相关的信息来描述它。还可以将所有大型材料加载到 RAM 中。然而,对于频繁使用大型 文本文件 的应用程序,例如 MS Word文本编辑器,则不建议这样做。

Donald Knuth 在计算机编程中引入了一种解决方案来解决这个问题。根据 Donald Knuth 的说法,我们可以完全抛弃堆栈概念。我们不需要允许调用者或被调用者经历任何过程。只需将它们视为合作的对等体。

C++ 中的协程实现

为了实现 C++ 协程,必须满足以下两个条件:

  • 在之前的状态下恢复控制
  • 通过调用创建持久数据

如上所述,可以 静态变量 来解决问题。但是,您如何记住状态也回到了与前一个时刻相同的执行状态,即返回或循环之后的代码行?这里 GOTO 语句 是适用的。让我们看下面的代码。

让我们举一个例子来理解如何在 C++ 中使用协程。

编码

输出

control at main :1
control at range
control at main :2
control at range
control at main :3
control at range
control at main :4
control at range

说明

在此示例中,在 for 循环 内定义了许多返回语句。我们实际上每次都返回到不同的状态,如果程序配置为这样做,就会执行它。这种方法模仿了 Python 函数 称为 range 函数。C++ 协程概念也是该 Python 函数的基础。

C++ 中的协程如何工作?

C++ 中的协程如下工作:

当 C++ 协程的主要执行完成时,它仍然可以在以后继续。主函数主要由 C++ 协程 调用,之后数据被保存在其他地方。协程 是函数,为了使它们工作,我们必须将它们的数据类型与它们关联起来。

C++ 协程 是出色的协程,因为它们总是与可变参数和返回语句相关联。但仍存在一些限制。主函数、常量表达式函数、构造函数析构函数 无法创建完美的协程。

使用协程的执行范式

有两个事物与 C++ 协程相关。第一个是 promise 对象,第二个是 coroutine 对象promise 对象 是一个对象,它提供了一个同步点,并且可以包含一个值,该值可以被任何未来的 a=object(通常是另一个线程)获取。此外,在以高效方式提供协程状态时,会使用堆。状态对象具有以下特征:

参数选项。

  • 局部变量临时变量 的有效期和范围仅限于当前的暂停点。
  • 其中的 promise 可操作项。
  • 我们表示 局部变量 的适当状态和值,以了解在哪里恢复和继续执行。

协程的句柄

当我们想在 协程帧 之外构建和执行代码时,我们会使用协程句柄。我们使用协程的 非使用处理程序 来恢复协程的执行,同时从帧中移除 C++ 协程。C++ 协程句柄在某种程度上类似于 c 指针,可以轻松地 复制,但我们没有析构函数来清除它占用的内存。因此,我们必须使用 coroutine_handle::destroy 方法来终止协程并防止内存泄漏。当协程被销毁时,指向被删除协程的协程句柄将被移除。现在它指向一个垃圾值,因此当调用协程句柄时,它将不再起作用。

标准返回对象

C++ 协程返回一个具有嵌套 type::promise_type 作为其返回类型的对象。名为 r get_return_object 的方法,它返回一个 type r 的外部对象,应该包含在 r::promise_type 中。协程函数是 get_return_object 函数 的结果。

promise 对象

协程状态中存在一个 promise 类型 的实例。我们可以添加一个名为 value 的字段来将值从协程传输到主函数。协程句柄被保留为 std::coroutine_handle<ReturnObject3::promise_type> 而不是转换为 std::coroutine_handle<>

co_yield 运算符

co_yield 运算符 将它从表达式中 yield 的值返回给调用者。它是可恢复生成器函数最受欢迎的组件之一,它会挂起正在运行的协程。

co_return 运算符

当使用 co_return 运算符 时,协程结束。可以通过三种方式进行信号通知:

  1. 可以使用 Co_return e 返回 值 e
  2. co_routine 可以使用 co_return 运算符 来表示协程的结束,而无需最终值。
  3. 与前一点类似,我们可以使用 co_return 运算符 来跳出函数末尾。

使用协程时需要注意的事项

我们永远不应忘记,以下是使用 C++ 协程的一些关键注意事项:

  • C++ 协程唯一可用的 运算符co_return;不支持 return。
  • 禁止使用 varargsconstexpr
  • 不允许 构造函数析构函数
  • 主函数 也不能包含协程。
  • 为了安全起见并防止悬空引用,在使用 C++ 协程时应按值使用参数。

引用参数和协程

实现 C++ 协程时,在协程挂起时不会保存完整的 调用堆栈。它只存储局部变量。基于堆栈 的完整协程是协程的一种 实现。另一方面,我们有 无堆栈协程,它保存和恢复 完整的调用堆栈。与任何其他 异步参数 类似,协程引用参数需要调用对象必须提供的引用参数。通过这样做,可以确保链接对象在对象持续时间内存在。

编码

输出

-4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111 116 121

示例 2

在此示例中,从输出返回的值使用 C++ 协程进行了存储。

编码

输出

fut_1.get(): 2022

结论

  1. C++ 中的 协程 是一种 控制结构,其中 控制流 在不同例程之间传递而不停止。
  2. 之后,C++ 协程从 C++11 开始引入。
  3. C++ 协程使用的 基于堆栈的操作
  4. 即使在 主要执行 完成后,C++ 协程也是可以稍后继续执行的函数。
  5. promise 对象coroutine 对象 是与 C++ 协程相关的两个事物。
  6. 协程句柄 用于 停止暂停 当前正在运行的协程。