Boost.Asio中有两处涉及协程,本文介绍其中的coroutine类。
Boost.Asio中的stackless协程是由coroutine类和一些宏来实现的。coroutine类非常简单,包括四个函数,一个int类型变量,用来保存当前函数的运行状态,与之配合使用的宏中,因采用switch来实现,所以可以根据这个整型变量的值实现跳转。
Boost.Asio定义了一些宏,构成所谓的“伪关键字”
reenter
reenter用来定义协程内容,用法如下:
reenter (coroutine变量)
{
... coroutine body ...
}
上面代码块如在成员函数内,coroutine变量用this,否则是变量名,最好别在body中定义变量,否则有麻烦(reenter的实现是用switch来做的)。
yield
yield的用法大致如下:
yield … 或 yield { … }
yield return
yield后加return,则reenter块后的代码不执行了。
yield;
本次进入reenter块什么都不做,但计数会增加
yield break
终止,再也不会进入reenter块
fork
fork用于“复制”协程,类似于unix的fork,程序先执行fork的代码,完毕后,再接着运行fork下一行代码。
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
=====
=====
=====
程序运行示意图
通讯过程中stackless协程的用法示例(Boost.asio文档中示例)
struct session : boost::asio::coroutine
{
boost::shared_ptr<tcp::socket> socket_;
boost::shared_ptr<std::vector<char> > buffer_;
session(boost::shared_ptr<tcp::socket> socket)
: socket_(socket), buffer_(new std::vector<char>(1024))
{
}
void operator()(boost::system::error_code ec = boost::system::error_code(), std::size_t n = 0)
{
if (!ec) reenter (this)
{
for (;;)
{
yield socket_->async_read_some(boost::asio::buffer(*buffer_), *this);
yield boost::asio::async_write(*socket_, boost::asio::buffer(*buffer_, n), *this);
}
}
}
};
需要说明的是,reenter中采用for循环后,运行顺序就变成了第一个yield,第二个yield,第一个yield…