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

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. ssh、scp免秘钥远程执行命令:expect

    首先安装expect # yum -y install expect 命令格式 # ./expect IP COMM    #expect是独立的工具,所以不能用sh来执行 1 2 3 4 5 6 7 ...

  2. Carbondata源码系列(二)文件格式详解

    在上一章当中,写了文件的生成过程.这一章主要讲解文件格式(V3版本)的具体细节. 1.字典文件格式详解 字典文件的作用是在存储的时候将字符串等类型转换为int类型,好处主要有两点: 1.减少存储占用空 ...

  3. 03.redis与ssm整合(mybatis二级缓存)

    SSM+redis整合 ssm框架之前已经搭建过了,这里不再做代码复制工作. 这里主要是利用redis去做mybatis的二级缓存,mybaits映射文件中所有的select都会刷新已有缓存,如果不存 ...

  4. 51Nod--1085背包问题

    1085 背包问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2--Wn(Wi为整 ...

  5. HDU3790-最短路径问题

    最短路径问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  6. SQL面试题:有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列

    .请教一个面试中遇到的SQL语句的查询问题 表中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列. ------------------- ...

  7. c# 初识WPF

    WPF,全名是Windows Presentation Foundation,是微软在.net3.0 WinFX中提出的.WPF是对Direct3D的托管封装,它的图形表现依赖于显卡.当然,作为一种更 ...

  8. Dagger2进阶必备技能

    之前写过一篇文章介绍Dagger2的初步知识, 本篇文章主要介绍Dagger2的进阶知识点. 主要包含的内有有 @Binds与@Provides的使用 Provider与Lazy的使用 依赖与包含 D ...

  9. QT制作一个图片播放器

    前言:使用qt制作了一个简单的图片播放器,可以播放gif.png等格式图片 先来看看播放器的功能(当然是很简陋的,没有很深入的设计): 1.点击图片列表中图片进行播放. 2.自动播放,播放的图片的间隔 ...

  10. Sql Server 新的日期类型

    新的日期类型:是出现在2008中的在2005中没有的日期类型. 1,Date 数据类型  2,time 数据类型  3, datetime2 数据类型  4, datetimeoffset 数据类型 ...