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

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. 解决thymeleaf layout布局不生效

    今天使用thymeleaf layout布局时总是不生效,特此把解决问题的步骤和几个关键点记录下来备忘. 一.检查依赖 1.thymeleaf必备maven依赖: <dependency> ...

  2. 校门外的树-poj

    问题描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  3. C语言之阶乘

    #include<stdio.h>#include<stdlib.h>#include<time.h>int main(){ int num,i,result=1; ...

  4. Ubuntu 17.04 安装

    不忘初心,方得始终. 今天听别人说17.04发布了,我是开心的不得了,赶紧下载了一个,准备安装在自己的本子上.这段时间已经花费了更多的时间在docker和OpenStack上面,没时间看新闻了,因此今 ...

  5. CCF-201604-1-折点计数

    问题描述 试题编号: 201604-1 试题名称: 折点计数 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给定n个整数表示一个商店连续n天的销售量.如果某天之前销售量在增长 ...

  6. UWP ListView下模板宽度问题

    在ListView中模板的宽度默认不会根据listView的宽度改变为改变,这需要更改一下设置,重点在于设置HorizontalContentAlignment的拉伸模式.注意是HorizontalC ...

  7. vue 二进制文件的下载(解决乱码和解压报错)

    问题描述:项目中使用的是vue框架进行开发,因为文件下载存在权限问题,所以并不能通过 a 链接的 href 属性直接赋值 URL进行下载, (如果你的文件没有下载权限,可以直接通过href属性赋值UR ...

  8. 智能合约语言 Solidity 教程系列4 - 数据存储位置分析

    写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么 这部分的内容官方英文文档讲的不是很透,因此我在参考Soli ...

  9. VBScripts and UAC elevation(visa以后的系统)

    这两天由于工作须要.在写一些vbs的脚本,才知道.vbs不能像其它可运行文件一样.在 须要提升訪问权限时.弹出UAC窗体.那么,怎样通过UAC提升vbs脚本的訪问权限呢? 查了一些资料,将结果整理一下 ...

  10. 自学Zabbix3.6.4-触发器triggers dependencies依赖关系

    有时,一个主机的可用性取决于另一个主机.如果路由器坏了,某个路由器后面的服务器就会变得不可访问.对于两个主机都配置了触发器,您可能会收到两个主机的通知,而只有路由器是有罪的一方.这是主机之间的一些依赖 ...