当前位置: 首页 > news >正文

广州番禺网站建设公司邯郸网站优化

广州番禺网站建设公司,邯郸网站优化,做网站点,做营销网站建设价格C20协程示例 认识协程 在C中&#xff0c;协程就是一个可以暂停和恢复的函数。 包含co_wait、co_yield、co_return关键字的都可以叫协程。 看一个例子&#xff1a; MyCoroGenerator<int> testFunc(int n) {std::cout << "Begin testFunc" << s…

C++20协程示例

认识协程

在C++中,协程就是一个可以暂停和恢复的函数。

包含co_waitco_yieldco_return关键字的都可以叫协程。

看一个例子:

MyCoroGenerator<int> testFunc(int n)
{std::cout << "Begin testFunc" << std::endl;for (int i = 0; i < n; ++i) {std::cout << "TestFunc before yield " << i << std::endl;co_yield i;std::cout << "TestFunc after yield " << i << std::endl;}std::cout << "End testFunc" << std::endl;
}int main()
{int inp = 10;std::cout << "Before testFunc" << std::endl;MyCoroGenerator<int> gen = testFunc(inp);std::cout << "After testFunc" << std::endl;for (int i = 0; i < inp; ++i) {std::cout << "Cur input: " << i << std::endl;std::cout << "Output value: " << gen.next() << std::endl;std::cout << "After input: " << i << std::endl;}
}

上面这段代码的执行结果是:

Before testFunc
After testFunc
Cur input: 0
Output value: Begin testFunc
TestFunc before yield 0
0
After input: 0
Cur input: 1
Output value: TestFunc after yield 0
TestFunc before yield 1
1
After input: 1
Cur input: 2
Output value: TestFunc after yield 1
TestFunc before yield 2
2
After input: 2
Cur input: 3
Output value: TestFunc after yield 2
TestFunc before yield 3
3
After input: 3
Cur input: 4
Output value: TestFunc after yield 3
TestFunc before yield 4
4
After input: 4
Cur input: 5
Output value: TestFunc after yield 4
TestFunc before yield 5
5
After input: 5...

调用时发现,函数并没有一开始就执行,而是等到next时才开始执行。执行到co_yield就会自动暂停,下次next才会继续执行

另外,函数本身并没有返回什么,但是这里可以使用MyCoroGenerator<int>接收。函数的控制权也转移到了MyCoroGenerator<int>,需要执行时就调用next

函数在暂停后执行,依然可以继续上次的状态,这是因为,协程在挂起期间,其上下文全部都被保留,下次执行时恢复。

协程句柄

std::coroutine_handle类模板是实现协程的最底层的工具,负责存储协程的句柄。他可以特化为std::coroutine_handle<Promise>或者std::coroutine_handle<void>

这里面的Promise是实现协程必要的Promise类,而且其名字必须是promise_type

协程会暂停,其上下文也会保留,std::coroutine_handle就是保存和管理协程的地方。

std::coroutine_handle中方法不多,但是每个都很重要,其中:

  • done方法,可以查询协程是否已经结束
  • resume,恢复一个协程的执行
  • destroy,销毁一个协程

std::coroutine_handle是一个很底层的东西,没有RAII包裹,就像一个裸指针那样,需要手动创建、手动销毁。

所以需要一个包裹类,负责处理协程句柄的初始化和销毁,也就是Generator

Generator

C++的协程要求Generator必须有promise_type这个类,名字也必须这个,不能是其他的名字,直接定义在Generator中最方便。

template <typename T>
struct MyCoroGenerator {struct promise_type {// todo};
};

promise_type中有一些固定接口,这些接口如果不实现,那么协程是不完整的。

  • initial_suspend,协程是否在初始化结束后挂起,返回std::suspend_always、std::suspend_never,这是标准库里面已经定义好的类型,前者表示总是挂起,后者表示从不挂起
  • final_suspend,协程最后一次执行是否挂起,返回值和上面函数相同。由于final_suspend是收尾阶段的工作,所以必须是noexcept
  • unhandled_exception,处理协程中未被处理的异常
  • get_return_object,返回一个Generator对象
  • yield_value,处理协程返回值,就是co_yield传递过来的值
  • return_void,处理协程结束后的返回值,和return_value同时只能存在一个,如果没有返回值就用return_void
  • return_value,处理协程结束后返回值,和return_void同时只能存在一个,如果有返回值就用return_value

解释一下yield_value函数,co_yield实际是一个语法糖,相当于co_wait promise.yield_value(i),只有实现了该函数,Genreator才能接收co_yield的返回值

函数的返回值,需要回答协程要不要挂起,也就是std::suspend_always或者std::suspend_never,因为需要yield后挂起,所以返回std::suspend_always

为了接收返回值,需要用转发和std::optional,接收并存储返回值。

get_return_object负责创建一个Generator,一般来说,使用std::coroutine_handle<promise_type>::from_promise接口从一个Promise创建句柄,然后使用这个句柄创建Generator。

为了配合创建函数,MyGenerator需要实现一个接收句柄的构造函数。也就是MyCoroGenerator(std::coroutine_handle<promise_type> h)

#include <coroutine>
#include <iostream>
#include <optional>template <typename T>
struct MyCoroGenerator {/*** @brief C++协程要求Generator必须有promise_type这个类型,名字也必须是promise_type* 最方便的方法就是定义在Generator类内部**/struct promise_type {/*** @brief 存放协程返回值* 由Generator从获取并返回*/std::optional<T> opt;/*** @brief 协程是否创建时就被挂起,函数名字也必须是initial_suspend* std::suspend_always、std::suspend_never是标准库里面已经定义好的类型,前者表示总是挂起,后者表示从不挂起** @return std::suspend_always 协程创建即挂起*/std::suspend_always initial_suspend() const{return {};}/*** @brief 协程最后一次执行是否挂起,函数名字也必须是final_suspend* 由于final_suspend是收尾阶段的工作,所以必须是noexcept** @return std::suspend_always 协程最后一次执行也被挂起*/std::suspend_always final_suspend() const noexcept{return {};}/*** @brief 处理协程中未捕获异常,函数名字必须是unhandled_exception**/void unhandled_exception(){std::exit(EXIT_FAILURE);}/*** @brief 获取一个Generator对象,该对象从promise_type构造** @return MyCoroGenerator*/MyCoroGenerator get_return_object(){return MyCoroGenerator { std::coroutine_handle<promise_type>::from_promise(*this) };}/*** @brief 定制yield_value接口,接收co_yield返回的值** @tparam Arg 值的类型* @param arg co_yield返回值* @return std::suspend_always 执行完后继续挂起*/template <typename Arg>std::suspend_always yield_value(Arg&& arg){opt.emplace(std::forward<Arg>(arg));return {};}/*** @brief 当协程结束co_return且没有返回值时,调用该函数* 还有一个return_value(expr)函数,负责处理协程结束且有返回值的情况*/void return_void(){}};/*** @brief 协程句柄,存储了协程上下文,一个非常底层的东西,没有RAII* 用MyCoroGenerator包裹*/std::coroutine_handle<promise_type> handle;/*** @brief 默认构造函数**/MyCoroGenerator() = default;/*** @brief 通过一个handle构造一个Generator** @param h 从promise_type构造出来的协程句柄*/MyCoroGenerator(std::coroutine_handle<promise_type> h): handle(h){}/*** @brief 移动构造函数** @param other 其他Generator对象*/MyCoroGenerator(MyCoroGenerator&& other){if (handle) {handle.destroy();}handle = other.handle;other.handle = nullptr;}/*** @brief 析构函数**/~MyCoroGenerator(){if (handle) {handle.destroy();}}/*** @brief 移动赋值函数** @param other 其他Generator对象* @return MyCoroGenerator& 当前镀锡*/MyCoroGenerator& operator=(MyCoroGenerator&& other){if (handle) {handle.destroy();}handle = other.handle;other.handle = nullptr;return *this;}/*** @brief 继续执行协程,并返回执行结果** @return T& 返回的值*/T& next(){handle.resume();if (handle.done()) {// throw geneator_done("Generator done");throw "Generator Error";}return *(handle.promise().opt);}private:MyCoroGenerator(const MyCoroGenerator&) = delete;MyCoroGenerator& operator=(const MyCoroGenerator&) = delete;
};

源码

#include <coroutine>
#include <iostream>
#include <optional>template <typename T>
struct MyCoroGenerator {/*** @brief C++协程要求Generator必须有promise_type这个类型,名字也必须是promise_type* 最方便的方法就是定义在Generator类内部**/struct promise_type {/*** @brief 存放协程返回值* 由Generator从获取并返回*/std::optional<T> opt;/*** @brief 协程是否创建时就被挂起,函数名字也必须是initial_suspend* std::suspend_always、std::suspend_never是标准库里面已经定义好的类型,前者表示总是挂起,后者表示从不挂起** @return std::suspend_always 协程创建即挂起*/std::suspend_always initial_suspend() const{return {};}/*** @brief 协程最后一次执行是否挂起,函数名字也必须是final_suspend* 由于final_suspend是收尾阶段的工作,所以必须是noexcept** @return std::suspend_always 协程最后一次执行也被挂起*/std::suspend_always final_suspend() const noexcept{return {};}/*** @brief 处理协程中未捕获异常,函数名字必须是unhandled_exception**/void unhandled_exception(){std::exit(EXIT_FAILURE);}/*** @brief 获取一个Generator对象,该对象从promise_type构造** @return MyCoroGenerator*/MyCoroGenerator get_return_object(){return MyCoroGenerator { std::coroutine_handle<promise_type>::from_promise(*this) };}/*** @brief 定制yield_value接口,接收co_yield返回的值** @tparam Arg 值的类型* @param arg co_yield返回值* @return std::suspend_always 执行完后继续挂起*/template <typename Arg>std::suspend_always yield_value(Arg&& arg){opt.emplace(std::forward<Arg>(arg));return {};}/*** @brief 当协程结束co_return且没有返回值时,调用该函数* 还有一个return_value(expr)函数,负责处理协程结束且有返回值的情况*/void return_void(){}};/*** @brief 协程句柄,存储了协程上下文,一个非常底层的东西,没有RAII* 用MyCoroGenerator包裹*/std::coroutine_handle<promise_type> handle;/*** @brief 默认构造函数**/MyCoroGenerator() = default;/*** @brief 通过一个handle构造一个Generator** @param h 从promise_type构造出来的协程句柄*/MyCoroGenerator(std::coroutine_handle<promise_type> h): handle(h){}/*** @brief 移动构造函数** @param other 其他Generator对象*/MyCoroGenerator(MyCoroGenerator&& other){if (handle) {handle.destroy();}handle = other.handle;other.handle = nullptr;}/*** @brief 析构函数**/~MyCoroGenerator(){if (handle) {handle.destroy();}}/*** @brief 移动赋值函数** @param other 其他Generator对象* @return MyCoroGenerator& 当前镀锡*/MyCoroGenerator& operator=(MyCoroGenerator&& other){if (handle) {handle.destroy();}handle = other.handle;other.handle = nullptr;return *this;}/*** @brief 继续执行协程,并返回执行结果** @return T& 返回的值*/T& next(){handle.resume();if (handle.done()) {// throw geneator_done("Generator done");throw "Generator Error";}return *(handle.promise().opt);}private:MyCoroGenerator(const MyCoroGenerator&) = delete;MyCoroGenerator& operator=(const MyCoroGenerator&) = delete;
};MyCoroGenerator<int> testFunc(int n)
{std::cout << "Begin testFunc" << std::endl;for (int i = 0; i < n; ++i) {std::cout << "TestFunc before yield " << i << std::endl;co_yield i;std::cout << "TestFunc after yield " << i << std::endl;}std::cout << "End testFunc" << std::endl;
}int main()
{int inp = 10;std::cout << "Before testFunc" << std::endl;MyCoroGenerator<int> gen = testFunc(inp);std::cout << "After testFunc" << std::endl;for (int i = 0; i < inp; ++i) {std::cout << "Cur input: " << i << std::endl;std::cout << "Output value: " << gen.next() << std::endl;std::cout << "After input: " << i << std::endl;}
}

参考:C++ coroutine generator 实现笔记

http://www.wangmingla.cn/news/123208.html

相关文章:

  • 做网站用矢量图还是位图百度一下你就知道官页
  • 购物网站开发教程湖南长沙疫情最新消息
  • 二级网站的建设方案深圳seo秘籍
  • 雨发建设集团有限公司网站襄阳seo推广
  • 东风地区网站建设公司一个企业该如何进行网络营销
  • 白云鄂博矿网站建设深圳网络推广收费标准
  • 天津做网站公司泉州百度竞价开户
  • 网站站内链接怎么做网站推广交换链接
  • 子页网站设计代运营电商公司
  • 哪个网站做课件能赚钱2023年8月疫情严重吗
  • 做营销网站公司放单平台
  • 做网站虚拟主机要多大水果网络营销策划书
  • 做深度的互联网站排名优化软件点击
  • 微网站是什么深圳网络公司推广公司
  • html5登录界面完整代码百度爱采购怎么优化排名
  • 个人帮企业做网站百度竞价代理商
  • 百度站长工具后台域名邮箱 400电话
  • 个人优惠券网站怎么做成都百度搜索排名优化
  • 官方网站建设的四个步骤百度指数电脑端查询
  • 京东门户网站怎么做开发一款app软件需要多少钱
  • 公司建站方案小红书推广方案
  • 网站风格的设计谷歌seo排名
  • 网页传奇怎么赚钱合肥网站seo推广
  • 创建网站的准备自己怎么制作一个网站
  • 怎么给自己的公司做网站基本seo
  • 宜阳县住房和城乡建设局网站福建百度代理公司
  • 学校网站查询学历口碑营销的优缺点
  • 滴滴优惠券网站怎么做seo培训优化
  • 在线自动取名网站怎么做怎么做起泡胶
  • 网站建设的七个流程步骤管理系统