具体的协程的基本使用可以参考:
Boost中的协程—Boost.Coroutine2(这篇博文很详细,唯一美中不足的是有处笔误,在本文最后指出,并做了更正)
协程介绍和boos中的协程实现——Boost.Coroutine2
我记录一下上面博文中忽略的一个很重要,也容易混淆的一点,这个会影响我们正常使用boost::coroutines2。
我们先看看两个类似的例子:
例子一:
#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 ";
std::cout << std::endl;
if (!source)
{
std::cout << "soure is not valid" << std::endl;
}
getchar();
return 0;
}
运行结果:
a=1 b=2 c=3
soure is not valid
例子二:
#include <iostream>
#include <typeinfo>
#include "boost/coroutine2/all.hpp"
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=";
source();
std::cout << std::endl;
if (!source)
{
std::cout << "soure is not valid" << std::endl;
}
getchar();
return 0;
}
运行结果:
1=a 2=b 3=c
soure is not valid
看到这两个类似的程序,结果却不同,困惑就产生了。我们来查资料解决困惑。
在Class coroutine<>::pull_type
template< typename Fn > pull_type( Fn && fn)
Effects:
Creates a coroutine which will execute fn, and enters it.
创建一个将来会执行Fn的coroutine,并且进入该Fn。意思是说,pull_type类型的,在构造完成后,就会调用一次Fn。
我们再来看看Class coroutine<>::push_type
template< typename Fn > push_type( Fn && fn)
Effects:
Creates a coroutine which will execute fn.
差别就出现了。push_type只是创建一个将来会执行fn的coroutine,但是创建好后,并不马上执行这个fn。
接下来我们看看if (!source)是怎么回事。以pull_type为例(push_type也是类似的)
#include <boost/coroutine2/coroutine.hpp>
template< typename R >
class coroutine<>::pull_type
{
public:
template< typename Fn >
pull_type( Fn && fn);
template< typename StackAllocator, typename Fn >
pull_type( StackAllocator stack_alloc, Fn && fn);
pull_type( pull_type const& other)=delete;
pull_type & operator=( pull_type const& other)=delete;
~pull_type();
pull_type( pull_type && other) noexcept;
pull_type & operator=( pull_type && other) noexcept;
pull_coroutine & operator()();
explicit operator bool() const noexcept;
bool operator!() const noexcept;
R get() noexcept;
};
template< typename R >
range_iterator< pull_type< R > >::type begin( pull_type< R > &);
template< typename R >
range_iterator< pull_type< R > >::type end( pull_type< R > &);
我们发现它重载了布尔运算符
explicit operator bool() const noexcept;
bool operator!() const noexcept;
也就是说我们可以通过判断它的bool值,来判断它是否有效。当它无效的时候,我们就不能再调用它去执行Fn了。
我们来看看它的实现:
template< typename T >
pull_coroutine< T >::operator bool() const noexcept {
return nullptr != cb_ && cb_->valid();
}
template< typename T >
bool
pull_coroutine< T >::operator!() const noexcept {
return nullptr == cb_ || ! cb_->valid();
}
很简洁,先判断回调cb是否为nullptr,如果不为nullptr,再检查cb是否有效。
参考:
协程介绍和boos中的协程实现——Boost.Coroutine2
Boost中的协程—Boost.Coroutine2
这篇博文也写得不错,就是可能说出现了一处笔误:
coroutine<>::pull_type在构造函数时,调用了一次协程函数(注意示例1的输出),而coroutine<>::pull_type没有。
应该是:
coroutine<>::pull_type在构造函数时,调用了一次协程函数(注意示例1的输出),而coroutine<>::push_type却不会马上执行一次协程函数。
(个人的体会,也通过官网的资料和源码证实了)