boost 1_66 无栈协程 coroutine 学习
安装boost库
yum直接安装:
1、yum install boost
2、yum install boost-devel
3、yum install boosat-doc
PS:注意yum安装的版本,有些旧boost版本还没有协程库
手动编译安装 boost_1_66_0.tar.gz
1、tar -vxzf boost_1_66_0.tar.gz
2、cd boost_1_66_0
3、./bootstrap.sh
4、./b2 install --prefix=/usr
5、ldconfig -v
检验是否安装成功
#include#include #include using namespace std; int main() { cout << "BOOST_VERSION: " << BOOST_VERSION << endl; cout << "BOOST_LIB_VERSION: " << BOOST_LIB_VERSION << endl; cout << "BOOST_PLATFORM: " << BOOST_PLATFORM << endl; cout << "BOOST_COMPILER: " << BOOST_COMPILER << endl; cout << "BOOST_STDLIB: " << BOOST_STDLIB << endl; return 0; }
执行结果
BOOST_VERSION: 106600
BOOST_LIB_VERSION: 1_66
BOOST_PLATFORM: linux
BOOST_COMPILER: GNU C++ version 4.8.5 20150623 (Red Hat 4.8.5-44)
BOOST_STDLIB: GNU libstdc++ version 20150623
安装成功
boost官网关于无栈协程介绍
主要来源于boost官网关于stackless协程的介绍
coroutine 类可以用来实现无栈的协程。这个类自身被用来保存协程的状态。
coroutine 类可以支持复制构造和赋值。最大一个int的空间占用。可以当作基类使用
reenter
用来定义一段协程,只接受一个coroutine的指针或引用,鉴于coroutine本身可以当作基类,你也可以用类似reenter(this) {…}的写法,当reenter被执行的时候,控制流会跳转到最后yield或者fork的位置。需要注意的是reenter宏是通过switch实现的,并不是类似线程那种上下文的保存和切换达到的,意味着当在协程体中使用局部变量的时候,重入协程体时候不能忽略局部变量的定义。
yield {statement}
常常用在异步 *** 作的时候,其执行的逻辑为:yield保存了当前协程的状态;其表达式初始化了异步 *** 作;定义恢复点为statement后的一条语句;控制流被转移到了协程体的结尾。当异步 *** 作结束的时候,函数对象重新被唤醒,然后reenter使得执行流转移到了恢复点。当然statement表达式也可以是复合表达式,用花括号框起,见boost_demo2
yield return {expression}
通常用于生成器的环境下使用,其return后面的值作为函数的返回值传递出来,同时不会继续执行reenter后的代码
yield break
主要用来终止协程的,yield首先设置协程的终止状体,然后流程被转移到了协程体的结尾。一旦终止,使用is_complete()就会返回true,同时协程不能够被再次reenter了。当然不一定要yield break,当流程执行到了协程体结尾,这些协程也会自动terminate了。这也很好理解,因为stackless协程的reenter本来就是用switch实现的。
fork {statement}
可以创建多个协程的拷贝,常用的情况是在服务端,协程被fork出来用于处理客户端的请求。父协程和子协程通过is_parent()、is_child()进行界定。
无栈协程源码
boost库中无栈协程的源码非常简洁明了且和boost其他的模块没有任何耦合,完全可以将该部分提出来单独使用,其源码只在boost/asio/coroutine.hpp和boost/asio/yield.hpp中,这里默认在Linux环境下运行,去掉一些编译相关的选项,源码只有如下这部分
include//coroutine_basic.h class coroutine_ref; class coroutine { public: /// Constructs a coroutine in its initial state. coroutine() : value_(0) {} /// Returns true if the coroutine is the child of a fork. bool is_child() const { return value_ < 0; } /// Returns true if the coroutine is the parent of a fork. bool is_parent() const { return !is_child(); } /// Returns true if the coroutine has reached its terminal state. bool is_complete() const { return value_ == -1; } private: friend class coroutine_ref; int value_; }; class coroutine_ref { public: coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} ~coroutine_ref() { if (!modified_) value_ = -1; } operator int() const { return value_; } int& operator=(int v) { modified_ = true; return value_ = v; } private: void operator=(const coroutine_ref&); int& value_; bool modified_; }; #define BOOST_ASIO_CORO_REENTER(c) switch (coroutine_ref _coro_value = c) case -1: if (_coro_value) { goto terminate_coroutine; terminate_coroutine: _coro_value = -1; goto bail_out_of_coroutine; bail_out_of_coroutine: break; } else case 0: #define BOOST_ASIO_CORO_YIELD_IMPL(n) for (_coro_value = (n);;) if (_coro_value == 0) { case (n): ; break; } else switch (_coro_value ? 0 : 1) for (;;) case -1: if (_coro_value) goto terminate_coroutine; else for (;;) case 1: if (_coro_value) goto bail_out_of_coroutine; else case 0: #define BOOST_ASIO_CORO_FORK_IMPL(n) for (_coro_value = -(n);; _coro_value = (n)) if (_coro_value == (n)) { case -(n): ; break; } else # define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__LINE__) # define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__LINE__) # define reenter(c) BOOST_ASIO_CORO_REENTER(c) # define yield BOOST_ASIO_CORO_YIELD # define fork BOOST_ASIO_CORO_FORK
在了解无栈协程的源码前,可以先了解一种C语言的编程技巧----达夫设备 Duff’s Device,其本意是通过程序员手动展开代码以减少循环次数,利用switch-case中case标签的fall-through特性,随着编译器的发展,现在很多编译器已经能自动去做这样一件事情了,可这个编程思路还是有助于我们实现一种朴素的协程,也就是上面代码中无栈协程的实现
#include "coroutine_basic.h" //上文中从boost库提取的无栈协程源码 #includeusing namespace std; coroutine c; void foo(int i) { cout << "before reenter " << i << endl; reenter(c) { yield cout << "foo1 " << i+1 << endl; yield cout << "foo2 " << i+1 << endl; } cout << "after reenter" << i << endl; } int main() { foo(1); foo(2); foo(3); return 0; }
运行结果
before reenter 1
foo1 2
after reenter1
before reenter 2
foo2 3
after reenter2
before reenter 3
after reenter3
看下该段示例代码的预编译后的foo函数代码片段
void foo(int i) { cout << "before reenter " << i << endl; switch (coroutine_ref _coro_value = c) case -1: if (_coro_value) { goto terminate_coroutine; terminate_coroutine: _coro_value = -1; goto bail_out_of_coroutine; bail_out_of_coroutine: break; } else case 0: { for (_coro_value = (12);;) if (_coro_value == 0) { case (12): ; break; } else switch (_coro_value ? 0 : 1) for (;;) case -1: if (_coro_value) goto terminate_coroutine; else for (;;) case 1: if (_coro_value) goto bail_out_of_coroutine; else case 0: cout << "foo1 " << i+1 << endl; for (_coro_value = (13);;) if (_coro_value == 0) { case (13): ; break; } else switch (_coro_value ? 0 : 1) for (;;) case -1: if (_coro_value) goto terminate_coroutine; else for (;;) case 1: if (_coro_value) goto bail_out_of_coroutine; else case 0: cout << "foo2 " << i+1 << endl; } cout << "after reenter" << i << endl; }
可以看到,可重入是通过传入函数的引用coroutine_ref _coro_value改变了全局变量coroutine c的value值,第二次进入foo函数后直接通过swith(12) break执行第13行。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)