协程可以很轻量的在子例程中进行切换,它由程序员进行子例程的调度(即切换)而不像线程那样需要内核参与,同时也省去了内核线程切换的开销,因为一个协程切换保留的就是函数调用栈和当前指令的寄存器,而线程切换需要陷入内核态,改变线程对象状态。

go把协程作为基础设施提供语言级的支持,cpp这种出了名的给程序员自由的语言肯定不会提供语言级的支持,而是通过准标准库boost coroutine2库(boost coroutine已经废弃,建议使用boost coroutine2)为cpp提供的协程支持。

这里有个来自boost coroutine2的例子可以说明协程的好处。假设有两个函数

(图片来自boost_1_65_1/libs/coroutine2/doc/html/coroutine2/intro.html)

协程可以在两个子例程之前轻松切换交错输出,不使用协程就就需要把两个子例程拆分成更小的子例程,如果期间涉及依赖上下文的计算那么拆分也不行,只能考虑setjump/longjump或者线程等解决方案,显然这样一来脑力复杂度,代码复杂度也就上来了。

协程分为对称协程(symmetric)和非对称协程(asymmetric),对称协程需要显式指定将控制权yeild给谁,非对称协程可以隐式的转移控制权给它的调用者,boost coroutine2实现的是非对称协程。

现在来实现上图的效果:

#include <iostream>
#include <boost/coroutine2/all.hpp> void foo(boost::coroutines2::coroutine<void>::push_type & sink){
std::cout << "a ";
sink();
std::cout << "b ";
sink();
std::cout << "c ";
} int main(){
boost::coroutines2::coroutine<void>::pull_type source(foo);
std::cout << "1 ";
source();
std::cout << "2 ";
source();
std::cout << "3 ";
getchar();
return ;
}

如果把push pull反过来会得到相反的输出:

void foo(boost::coroutines2::coroutine<void>::pull_type & sink1){
std::cout << "a ";
sink1();
std::cout << "b ";
sink1();
std::cout << "c ";
} int main(){
boost::coroutines2::coroutine<void>::push_type source(foo);
std::cout << "1 ";
source();
std::cout << "2 ";
source();
std::cout << "3 ";
return ;
}

模板参数为void的协程是特例化的实现,它比之普通的泛型协程少了get()和迭代器实现。

这里我们使用带返回值的协程,然后用get方法获取它的返回值:

#include <iostream>
#include <boost/coroutine2/all.hpp> void foo(boost::coroutines2::coroutine<std::string>::pull_type & sink){
std::cout << "get " << sink.get() << "from main() by foo()\n";
sink();
std::cout << "get " << sink.get() << "from main() by foo()\n";
sink();
} int main(){
std::string str1("HELLO");
std::string str2("WORLD");
boost::coroutines2::coroutine<std::string>::push_type source(foo);
std::cout << "pass " << str1 << " from main() to foo()\n";
source(str1);
std::cout << "pass " << str2 << " from main() to foo()\n";
source(str2);
return ;
}

不难看出push可以传入参数,pull可以接受参数。

现在再试试协程的迭代器,对了,协程的迭代器不支持后置++:

#include <iostream>
#include <boost/coroutine2/all.hpp>
#include <boost/coroutine2/detail/push_coroutine.hpp>
#include <boost/coroutine2/detail/pull_coroutine.hpp> constexpr int N = ; // 方法一:中规中矩
void foo(boost::coroutines2::coroutine<int>::pull_type & sink){
using coIter = boost::coroutines2::coroutine<int>::pull_type::iterator;
for (coIter start = begin(sink); start != end(sink); ++start) {
std::cout << "retrieve "<<*start << "\n";
}
}
// 方法二:auto自动推导
void foo2(boost::coroutines2::coroutine<int>::pull_type & sink) {
for (auto val : sink) {
std::cout << "retrieve " << val << "\n";
}
}
// 方法三:守旧
void foo3(boost::coroutines2::coroutine<int>::pull_type & sink) {
for (int i = ; i < N; i++) {
std::cout << "retrieve " << sink.get() << "\n";
sink();
}
} int main(){
boost::coroutines2::coroutine<int>::push_type source(foo2);
for (int i = ; i < N; i++) {
source(i);
}
return ;
}

Boost Coroutine2 - stackful coroutine简介的更多相关文章

  1. Boost.Coroutine2:学习使用Coroutine(协程)

    function(函数)routine(例程)coroutine (协程) 函数,例程以及协程都是指一系列的操作的集合. 函数(有返回值)以及例程(没有返回值)也被称作subroutine(子例程), ...

  2. Boost LRU-Cache使用方法简介

    缓存是提高系统运行效率的常用组件,可以将"有效的"业务数据直接返回用户,避免繁琐的计算过程.除了Redis.MemCache等常用缓存系统,应用程序内部也可以根据需要设置一定容量的 ...

  3. boost Asio网络编程简介

    :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...

  4. Boost - 从Coroutine2 到Fiber

    Boost - 从Coroutine2 到Fiber 协程引子 我开始一直搞不懂协程是什么,网上搜一搜,(尤其是Golang的goroutine)感觉从概念上听起来有点像线程池,尤其是类似Java的E ...

  5. Visual studio 2017编译 boost

    下载: https://www.boost.org/   或者 https://dl.bintray.com/boostorg/release/1.66.0/source/ 下载完成以后解压到自己想要 ...

  6. Array的简单使用(Boost和STL通用)

    目录 目录 介绍 使用 Boost和STL的区别 介绍 本来这一次是想简单介绍一下Boost里面的协程库的使用的,但是Boost.Coroutine已经被废弃了,而Boost.Coroutine2目前 ...

  7. C++17尝鲜

    https://cloud.tencent.com/developer/article/1351910 [译]C++17,optional, any, 和 variant 的更多细节 用户261520 ...

  8. Golang源码探索(二) 协程的实现原理

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱, 虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻 ...

  9. Golang源码探索(二) 协程的实现原理(转)

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱,虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻底 ...

随机推荐

  1. 解决No enclosing instance of type * is accessible

    写一个内部类,并在构造函数中初始化时,遇到报错,搜索问题后发现,有网友出现过类似的问题,下面这个是说的浅显明白的,并确实解决了问题.于是,以下内容照搬过来,不再多费键盘了. public class ...

  2. java 之 建造者模式(大话设计模式)

    建造者模式,在笔者看来比较试用于,定制一个业务流程,而流程的细节又不尽相同,每个细节又必不可少,这时应考虑使用建造者模式. 大话设计模式-类图 先看下笔者写的一个简单的例子. /** * 所有建造过程 ...

  3. Caddy服务器搭建和实现文件共享

    1:Caddy介绍 作为新兴 Web 服务器,Caddy 提供了很多简单易用的功能而没有历史的包袱,其默认支持并且能帮你自动配置 HTTP/2.HTTPS,对于 IPV6.WebSockets 都有很 ...

  4. java.lang.ClassCastException: com.sun.proxy.$Proxy2 cannot be cast to...异常

    异常: Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy2 cannot ...

  5. 51Nod1136--欧拉函数

    1136 欧拉函数 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目.此函数以其首名研究者欧拉命 ...

  6. HDU1864--01背包

    最大报销额 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  7. php 将pdf转成图片且将图片拼接

    说明: 1.pdf转图片通过安装php扩展imagick实现. 2.由于windows扩展安装的一系列问题,建议在linux环境开发,windows大伙可以尝试安装. 3.为Centos 安装Imag ...

  8. [P4基础]p4app的Docker镜像仓使用详解

    How to use the p4lang/p4app Docker image 本文参考 孙勇峰博客 和 p4app README 以及 p4app Dockerfile 结合自己的理解做一些记录, ...

  9. Android测试:Fundamentals of Testing

    原文地址:https://developer.android.com/training/testing/fundamentals.html 用户在不同的级别上与你的应用产生交互.从按下按钮到将信息下载 ...

  10. form表单提交和ajax提交优先级

    form中若定义action,那么,ajax将不能执行.form默认提交的请求优先级高于ajax