1 介绍
协程分为对称协程(symmetric)和非对称协程(asymmetric),对称协程需要显式指定将控制权yeild给谁,非对称协程可以隐式的转移控制权给它的调用者,boost coroutine2实现的是非对称协程.
Boost库中的协程支持两种方式:
一种是封装了Boost.Coroutine的spawn,是一个stackful类型的协程;
一种是asio作者写出的stackless协程。
Boost.Asio中的stackless协程是由coroutine类和一些宏来实现的。coroutine类非常简单,包括四个函数,一个int类型变量,用来保存当前函数的运行状态,与之配合使用的宏中,因采用switch来实现,所以可以根据这个整型变量的值实现跳转。
2 伪关键字
Boost.Asio定义了一些宏,构成所谓的“伪关键字”
2.1 reenter
reenter用来定义协程内容,用法如下:
reenter (coroutine变量)
{
... coroutine body ...
}
第N次执行reenter代码块时,对应执行reenter代码块中第N个yield/fock。
上面代码块如在成员函数内,coroutine变量用this,否则是变量名,最好别在body中定义变量,否则有麻烦(reenter的实现是用switch来做的)。
2.2 yield
yield的用法大致如下:
yield … 或 yield { … }
2.3 yield return
yield后加return,则reenter块后的代码不执行了。
2.4 yield;
本次进入reenter块什么都不做,但计数会增加
2.5 yield break
终止,再也不会进入reenter块
2.6 fork
fork用于“复制”协程,类似于unix的fork,程序先执行fork的代码,完毕后,再接着运行fork下一行代码。
3 例子
3.1 例子1
#include <boost/asio/yield.hpp>
#include <boost/asio/coroutine.hpp>
#include <iostream>
boost::asio::coroutine c;
void foo(int i)
{
reenter(c)
{
yield std::cout<<"foo1 "<<i<<std::endl;
fork foo(100);
yield std::cout<<"foo2 "<< i+1<<std::endl;
}
}
int main()
{
foo(1);
foo(2);
foo(3);
return 0;
}
这个程序的输出是。。。
foo1 1
foo2 101
foo2 3
这个咋看之下有点难以理解,我们先忽略具体的细节,解释一下这是怎么回事。
首先,我们需要声明一个corountine,然后将需要重复进入的代码用reenter包括起来。第一次调用foo的时候,代码执行到第一个yield,此时,foo直接返回。
第二次调用的时候,程序直接执行上一次yield之后的代码,即fork,此时,程序调用foo,需要注意的是,被调用的fork不再执行第一个yield,而是直接从当前语句开始执行,于是得到输出foo2 101,返回之后,程序调用fork之后的yield,得到输出foo2 3。
第三次调用的时候,由于不再有任何未执行的yield,因此不再产生任何输出。
从结果中可以看出:
第N次执行reenter代码块时,对应执行reenter代码块中第N个yield/fock。
3.2 例子2:
boost::asio::coroutine c;
boost::asio::coroutine c2;
void forkit(int i)
{
reenter(c2)
{
yield std::cout<<"forkit1 "<< i<<std::endl;
yield std::cout<<"forkit2 "<< i<<std::endl;
}
}
void foo(int i)
{
reenter(c)
{
yield
{
std::cout<<"foo1 "<<i<<std::endl;
return;
}
fork foo(10);
yield std::cout<<"foo2 "<< i<<std::endl;
fork forkit(100);
yield std::cout<<"foo3 "<< i<<std::endl;
yield break;
yield std::cout<<"foo4 "<< i<<std::endl;
}
printf("=====\n");
}
int main()
{
forkit(1);
foo(1);
foo(2);
foo(3);
foo(4);
foo(5);
return 0;
}
输出:
forkit1 1
foo1 1
foo2 10
=====
foo2 2
=====
forkit2 100
foo3 3
=====
=====
=====
程序运行示意图
参考:
https://blog.csdn.net/guxch/article/details/82804067
https://toutiao.io/posts/d2eeed/preview