C++ 中的协程

在本文中,我们将讨论协程、用途、实现、示例和输出。

什么是协程?
C++ 中的协程是一种控制结构,其中控制流不间断地从一个例程传输到另一个例程。C++20版本引入了C++协程功能。协程是一种可以阻止稍后恢复执行的方法。协程在开发的各个阶段的使用方式与使用一组有效的顺序代码非并发执行代码类似由于 C++协程具有无堆栈行为,因此该函数将结果提供给调用者。它继续指定的协程,该协程再次存储在已经声明的隔离区域或堆栈中。

为什么使用 C++ 协程?
你可以逐行读取一条记录,这也可以,或者你可以读入一些关键且相关的信息来描述它。将所有巨大的材料加载到RAM中也是可行的。但是,不建议经常使用大型文本文件的应用程序,例如MS Word和文本编辑器。

Donald Knuth在计算机编程中引入了一个解决方案来解决这个问题。根据Donald Knuth 的说法,我们可以完全废除堆栈概念。我们不需要让调用者或调用者经历任何流程。只需将它们视为平等合作即可。

C++ 中的协程实现
要实现 C++ 协程,必须满足以下两个条件:

  • 恢复之前状态的控制
  • 使用调用创建持久数据

如上所述,可以使用静态变量来解决该问题。但是你怎么记得状态也会回到刚才相同的执行状态,即return或循环后面的代码行。此处, GOTO 语句适用。我们看下面的代码。

int run(void)  
{  
  int i;  
  for (i = 0; i< 10; i++)  
    return i;   
}  

让我们举例说明如何在 C++ 中使用例行程序。

include <iostream>  
using namespace std;  
  
int range(int a, int b)  
{  
  static long long int i;  
  static int state = 0;  
  switch (state) {  
  case 0:   
    state = 1;  
    for (i = a; i< b; i++) {  
      return i;  
  
    case 1:  
cout<< "control at range"  
<<endl;   
    }  
  }  
  state = 0;  
  return 0;  
}  
  
  
int main()  
{  
  int i;   
  
  for (; i = range(1, 5);)  
cout<< "control at main :" <<i<<endl;  
  
  return 0;  
}  
输出:
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 函数。C++ 协程概念也是该 Python 函数的基础。

C++ 中协程如何运行?
C++ 中的协程的详细操作如下。

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

C++协程是优秀的协程,因为它们总是与变量参数和返回语句结合在一起。但仍然存在一些限制。主函数、常量表达式函数、构造函数和析构函数,无法创建完美的协程。

使用协程的执行范例:
有两件事与 C++ 协程相关。Promise对象是第一个,协程对象是第二个。Promise 对象是一个提供同步点的对象,并且可以包含可由任何将来的a=object (通常是另一个线程)获取的值。此外,当堆以有效的方式可用时,它会与协程状态一起使用。以下特征适用于状态对象:

参数选项。

  • 局部变量和临时变量在当前暂停点之前具有有限的时间戳和范围。
  • 承诺其中可操纵的物品。
  • 我们表示局部变量的适当状态和值,以了解在哪里恢复并继续执行。


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

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

承诺对象:
Promise类型实例存在于协程状态中。我们可以添加一个名为 value 的字段,将值从协程传输到主函数。协程句柄保留为std::coroutine_handleReturnObject3::promise_type>而不是转换为std::coroutine_handle>。

运算符 co_yield:
co_yield 运算符将从表达式生成的值返回给调用者。它是可恢复生成器函数中最流行的组件之一,它暂停正在运行的协程。

运算符 co_return:

当使用co_return 运算符时,协程将结束。信号发送可以通过三种方式之一完成。

  • 可以使用Co_return e返回值e。
  • co_routine可以利用co_return 运算符来指示协程的结束,而无需最终值。
  • 与前一点类似,我们可以使用co_return 运算符来脱离函数的末尾。

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

  • C++协程可用的唯一运算符是co_return;不支持退货。
  • 禁止使用varargs和 constexpr 。
  • 不允许使用构造函数和析构函数。
  • 主函数不能同时包含协程。
  • 在使用 C++ 协程时,我们应该按值使用参数,以确保安全并防止悬空引用。

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

include <iostream>  
include <vector>  
  
std::vector<int>get_the_greedy_Num(int start, int last, int inc = 1) {  
std::vector<int>greedy_nums;  
  for (int j_0 = start; j_0 < last; j_0 += inc) {  
greedy_nums.push_back(j_0);  
  }  
  return greedy_nums;  
}  
  
int main() {  
std::cout<< std::endl;  
  
const auto greedy_nums = get_the_greedy_Num(-4, 15);  
  for (auto n :greedy_nums)  
std::cout<< n << " ";  
std::cout<< "\n\n";  
  
  for (auto n :get_the_greedy_Num(1, 123, 5))  
std::cout<< n << " ";  
std::cout<< "\n\n";  
  
  return 0;  
}  
Output:

-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


在本例中,输出返回的值使用 C++ 正则表达式存储。

include <coroutine>  
include <iostream>  
include <memory>  
  
template<typename T_0>  
struct date_future {  
std::shared_ptr<T_0> value;  
date_future(std::shared_ptr<T_0> p_1) : value(p_1) {}  
  ~date_future() {}  
  
  T_0 get() {  
    return *value;  
  }  
  
  struct promise_type {  
std::shared_ptr<T_0>ptr = std::make_shared<T_0>();  
    ~promise_type() {}  
  
date_future<T_0>get_return_object() {  
      return ptr;  
    }  
  
    void return_value(T_0 k) {  
      *ptr = k;  
    }  
  
std::suspend_neverinitial_suspend() {  
      return {};  
    }  
  
std::suspend_neverfinal_suspend() noexcept {  
      return {};  
    }  
  
    void unhandled_exception() {  
std::exit(1);  
    }  
  };  
};  
  
date_future<int> createFuture_0(int year) {  
co_return year;  
}  
  
int main() {  
std::cout<< '\n';  
  auto fut_1 = createFuture_0(2022);  
std::cout<< "fut_1.get(): " << fut_1.get() << '\n';  
std::cout<< '\n';  
  
  return 0;  
}  

Output:
fut_1.get(): 2022

​​​​​​​结论

  • C++ 中的例程是一种控制结构,在这种结构中,控制流不间断地从一个例程传输到另一个例程。
  • 此后,C++ 的例程从 C++11 开始引入。
  • C++coroutine 使用的基于栈的操作。
  • 即使在一次执行结束后,C++ coroutine 也是可以在以后继续执行的函数。
  • 许诺对象和例程对象是与 C++ 例程相关的两个东西。
  • coroutine 句柄用于停止或暂停正在运行的 coroutine。