前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Boost Coroutine2 - stackful coroutine简介

Boost Coroutine2 - stackful coroutine简介

作者头像
racaljk
发布2018-08-31 11:07:02
2.2K0
发布2018-08-31 11:07:02
举报
文章被收录于专栏:racaljkracaljk

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

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 0;
}

如果把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 0;
}

模板参数为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 0;
}

不难看出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 = 10;

// 方法一:中规中矩
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 = 0; i < N; i++) {
        std::cout << "retrieve " << sink.get() << "\n";
        sink();
    }
}

int main(){
    boost::coroutines2::coroutine<int>::push_type source(foo2);
    for (int i = 0; i < N; i++) {
        source(i);
    }
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-11-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档