C++ Boost Coroutine使用协程详解

目录
  • 一、说明语言扩展
  • 二、库Boost.Coroutine
  • 三、示例和代码

一、说明语言扩展

以下库扩展了编程语言 C++。

  • Boost.Coroutine 使得在 C++ 中使用协程成为可能——其他编程语言通常通过关键字 yield 支持。
  • Boost.Foreach 提供了一个基于范围的 for 循环,它是在 C++11 中添加到语言中的。
  • Boost.Parameter 允许您以名称/值对的形式并以任何顺序传递参数——例如,这在 Python 中是允许的。
  • Boost.Conversion 提供了两个转换运算符来替换 dynamic_cast 并允许您区分向下转换和交叉转换。

二、库Boost.Coroutine

通过 Boost.Coroutine,可以在 C++ 中使用协程。协程是其他编程语言的一个特性,通常使用关键字 yield 来表示协程。在这些编程语言中,yield 可以像 return 一样使用。但是,当使用 yield 时,该函数会记住该位置,如果再次调用该函数,将从该位置继续执行。

C++ 没有定义关键字 yield。但是,使用 Boost.Coroutine 可以从函数返回并稍后从同一位置继续。 Boost.Asio 库也使用 Boost.Coroutine 并受益于协程。

三、示例和代码

Boost.Coroutine 有两个版本。本章介绍第二个版本,即当前版本。这个版本从 Boost 1.55.0 开始可用,并取代了第一个版本。

示例 51.1。使用协程

#include <boost/coroutine/all.hpp>
#include <iostream>
using namespace boost::coroutines;
void cooperative(coroutine<void>::push_type &sink)
{
  std::cout << "Hello";
  sink();
  std::cout << "world";
}
int main()
{
  coroutine<void>::pull_type source{cooperative};
  std::cout << ", ";
  source();
  std::cout << "!\n";
}

Example51.1

示例 51.1 定义了一个函数 cooperative(),它作为协程从 main() 调用。 cooperative() 提前返回 main() 并被第二次调用。在第二次调用时,它会从中断处继续。

要将 cooperative() 用作协程,使用类型 pull_type 和 push_type。这些类型由 boost::coroutines::coroutine 提供,这是一个在示例 51.1 中用 void 实例化的模板。

要使用协程,您需要 pull_type 和 push_type。其中一种类型将用于创建一个对象,该对象将使用您想用作协程的函数进行初始化。另一种类型将是协程函数的第一个参数。

示例 51.1 在 main() 中创建了一个名为 source 的 pull_type 类型的对象。 cooperative() 传递给构造函数。 push_type 用作 cooperative() 签名中的唯一参数。

创建源时,传递给构造函数的函数 cooperative() 会立即作为协程调用。发生这种情况是因为源基于 pull_type。如果源基于 push_type,则构造函数不会将 cooperative() 作为协程调用。

cooperative() 将 Hello 写入标准输出。之后,函数像访问函数一样访问 sink 。这是可能的,因为 push_type 重载了 operator()。 main() 中的 source 表示协程 cooperative(),cooperative() 中的 sink 表示函数 main()。调用 sink 使 cooperative() 返回,而 main() 从调用 cooperative() 的地方继续,并将逗号写入标准输出。

然后,main() 调用 source 就好像它是一个函数一样。同样,这是可能的,因为重载了 operator()。这一次,cooperative() 从中断点继续并将世界写入标准输出。因为 cooperative() 中没有其他代码,协程结束。它返回到 main(),它将一个感叹号写入标准输出。

结果是示例 51.1 显示 Hello, world!

您可以将协程视为协作线程。在某种程度上,函数 main() 和 cooperative() 同时运行。代码在 main() 和 cooperative() 中轮流执行。每个函数内的指令按顺序执行。多亏了协程,一个函数不需要在另一个函数执行之前返回。

示例 51.2。从协程返回一个值

#include <boost/coroutine/all.hpp>
#include <functional>
#include <iostream>
using boost::coroutines::coroutine;
void cooperative(coroutine<int>::push_type &sink, int i)
{
  int j = i;
  sink(++j);
  sink(++j);
  std::cout << "end\n";
}
int main()
{
  using std::placeholders::_1;
  coroutine<int>::pull_type source{std::bind(cooperative, _1, 0)};
  std::cout << source.get() << '\n';
  source();
  std::cout << source.get() << '\n';
  source();
}

Example51.2

示例 51.2 与前面的示例类似。这次模板 boost::coroutines::coroutine 是用 int 实例化的。这使得从协程返回一个 int 给调用者成为可能。

传递 int 值的方向取决于使用 pull_type 和 push_type 的位置。该示例使用 pull_type 在 main() 中实例化一个对象。 cooperative() 可以访问 push_type 类型的对象。 push_type 发送一个值,pull_type 接收一个值;因此,设置了数据传输的方向。

cooperative() 调用 sink,参数类型为 int。此参数是必需的,因为协程是使用数据类型 int 实例化的。通过使用由 pull_type 提供的成员函数 get() 从 main() 中的 source 接收传递给 sink 的值。

示例 51.2 还说明了如何将具有多个参数的函数用作协程。 cooperative() 有一个额外的 int 类型参数,不能直接传递给 pull_type 的构造函数。该示例使用 std::bind() 将函数与 pull_type 链接起来。

该示例将 1 和 2 后跟 end 写入标准输出。

示例 51.3。将两个值传递给协程

#include <boost/coroutine/all.hpp>
#include <tuple>
#include <string>
#include <iostream>
using boost::coroutines::coroutine;
void cooperative(coroutine<std::tuple<int, std::string>>::pull_type &source)
{
  auto args = source.get();
  std::cout << std::get<0>(args) << " " << std::get<1>(args) << '\n';
  source();
  args = source.get();
  std::cout << std::get<0>(args) << " " << std::get<1>(args) << '\n';
}
int main()
{
  coroutine<std::tuple<int, std::string>>::push_type sink{cooperative};
  sink(std::make_tuple(0, "aaa"));
  sink(std::make_tuple(1, "bbb"));
  std::cout << "end\n";
}

Example51.3

示例 51.3 在 main() 中使用 push_type,在 cooperative() 中使用 pull_type,这意味着数据从调用方传输到协程。

此示例说明如何传递多个值。 Boost.Coroutine 不支持传递多个值,因此必须使用元组。您需要将多个值打包到元组或其他结构中。

示例 51.3 显示 0 aaa、1 bbb 和 end。

示例 51.4。协程和异常

#include <boost/coroutine/all.hpp>
#include <stdexcept>
#include <iostream>
using boost::coroutines::coroutine;
void cooperative(coroutine<void>::push_type &sink)
{
  sink();
  throw std::runtime_error("error");
}
int main()
{
  coroutine<void>::pull_type source{cooperative};
  try
  {
    source();
  }
  catch (const std::runtime_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

协程在抛出异常时立即返回。异常被传输到协程的调用者,在那里它可以被捕获。因此,异常与常规函数调用没有什么不同。

示例 51.4 显示了这是如何工作的。此示例会将字符串错误写入标准输出。

到此这篇关于C++ Boost Coroutine使用协程详解的文章就介绍到这了,更多相关C++ Boost Coroutine内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost Conversion超详细讲解

    目录 一.说明 二.示例和代码 三.更多示例代码 一.说明 Boost.Conversion 在头文件 boost/cast.hpp 中定义了转换运算符 boost::polymorphic_cast 和 boost::polymorphic_downcast.它们旨在更精确地处理类型转换——通常使用 dynamic_cast 完成. 库由两个文件组成.分别在boost/cast.hpp文件中定义了boost::polymorphic_cast和boost::polymorphic_downca

  • C++ Boost Random随机函数详解

    目录 一.说明 二.示例代码 一.说明 Boost.Random 库提供了许多随机数生成器,可让您决定应如何生成随机数.在 C++ 中,始终可以使用来自 cstdlib 的 std::rand() 生成随机数.但是,使用 std::rand() 生成随机数的方式取决于标准库的实现方式. 当包含头文件 boost/random.hpp 时,您可以使用 Boost.Random 中的所有随机数生成器和其他类和函数. 该库的大部分已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,您可

  • C++ Boost Exception超详细讲解

    Boost.Exception 库提供了一种新的异常类型 boost::exception,它允许您在抛出异常后将数据添加到异常中.此类型在 boost/exception/exception.hpp 中定义.由于 Boost.Exception 将其类和函数分布在多个头文件中,以下示例访问主头文件 boost/exception/all.hpp 以避免一个接一个地包含头文件. Boost.Exception 支持 C++11 标准的机制,该机制将异常从一个线程传输到另一个线程. boost::

  • C++ boost thread库用法详细讲解

    目录 一.说明 二.boost::thread的几个函数 三.构造 一.说明 boost::thread的六种使用方法总结,本文初步介绍线程的函数.构造.执行的详细解释. 二.boost::thread的几个函数 函数 功能 join() 让主进程等待子线程执行完毕后再继续执行 get_id() 获得线程的 id 号 detach() 标线程就成为了守护线程,驻留后台运行 bool joinable() 是否已经启动,为 join() thread::join()是个简单暴力的方法,主线程等待子

  • C++ Boost System超详细讲解

    目录 一.说明 二.关于 Boost.System库 一.说明 以下库支持错误处理. Boost.System 提供类来描述和识别错误.自 C++11 以来,这些类已成为标准库的一部分. Boost.Exception 使得在抛出异常后附加数据成为可能. 二.关于 Boost.System库 Boost.System Boost.System 是一个库,本质上定义了四个类来识别错误.所有四个类都已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,则无需使用 Boost.Syste

  • C++ Boost Accumulators累加器详细讲解

    Boost.Accumulators Boost.Accumulators 提供了处理样本的类.例如,您可以找到最大或最小的样本,或者计算所有样本的总和.虽然标准库支持其中一些操作,但 Boost.Accumulators 还支持统计计算,例如均值和标准差. 该库称为 Boost.Accumulators,因为累加器是一个基本概念.累加器是一个容器,每次插入一个值时都会计算出一个新的结果.该值不一定存储在累加器中.相反,累加器在输入新值时不断更新中间结果. Boost.Accumulators

  • C++ Boost log日志库超详细讲解

    目录 一.说明 二.库Boost.Log 一.说明 应用程序库是指通常专门用于独立应用程序开发而不用于库开发的库. Boost.Log 是一个日志库. Boost.ProgramOptions 是一个用于定义和解析命令行选项的库. Boost.Serialization 允许您序列化对象,例如,将它们保存到文件或从文件加载它们. Boost.Uuid 支持使用 UUID. 具体内容 62. Boost.Log 63. Boost.ProgramOptions 64. Boost.Serializ

  • C++ Boost Foreach超详细分析讲解

    目录 一.说明 二.示例代码 2.1 最简单的代码 2.2 使用BOOST_FOREACH与BOOST_REVERSE_FOREACH 三.BOOST_FOREACH特点和应用范围 四.遍历循环控制 一.说明 Boost.Foreach Boost.Foreach 提供了一个宏来模拟 C++11 中基于范围的 for 循环.您可以使用在 boost/foreach.hpp 中定义的宏 BOOST_FOREACH 来迭代序列而不使用迭代器.如果你的开发环境支持C++11,可以忽略Boost.For

  • C++ Boost Parameter超详细讲解

    目录 一.说明 二.示例代码 一.说明 Boost.Parameter 使得将参数作为键/值对传递成为可能.除了支持函数参数外,该库还支持模板参数. Boost.Parameter 在您使用长参数列表并且参数的顺序和含义难以记住时特别有用.键/值对使得以任何顺序传递参数成为可能.因为每一个值都是通过一个键来传递的,所以各种值的含义也更加清晰. 二.示例代码 示例 53.1.作为键/值对的函数参数 #include <boost/parameter.hpp> #include <strin

  • C++ Boost Coroutine使用协程详解

    目录 一.说明语言扩展 二.库Boost.Coroutine 三.示例和代码 一.说明语言扩展 以下库扩展了编程语言 C++. Boost.Coroutine 使得在 C++ 中使用协程成为可能——其他编程语言通常通过关键字 yield 支持. Boost.Foreach 提供了一个基于范围的 for 循环,它是在 C++11 中添加到语言中的. Boost.Parameter 允许您以名称/值对的形式并以任何顺序传递参数——例如,这在 Python 中是允许的. Boost.Conversio

  • Python3.10 Generator生成器Coroutine原生协程详解

    目录 引言 协程底层实现 业务场景 结语 引言 普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态.而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在Python3.10中,原生协程的实现手段,就是生成器,或者说的更具体一些:协程就是一种特殊的生成器,而生成器,就是协程的入门心法. 协程底层实现 我们知道,Python3.10中可以使用async和await关键字来实现原生协程函数的定义和调度,但其实,我们也可以利用生成器达到协程的效果,

  • python线程、进程和协程详解

    引言 解释器环境:python3.5.1 我们都知道python网络编程的两大必学模块socket和socketserver,其中的socketserver是一个支持IO多路复用和多线程.多进程的模块.一般我们在socketserver服务端代码中都会写这么一句: server = socketserver.ThreadingTCPServer(settings.IP_PORT, MyServer) ThreadingTCPServer这个类是一个支持多线程和TCP协议的socketserver

  • Python进阶之协程详解

    目录 协程 协程的应用场景 抢占式调度的缺点 用户态协同调度的优势 协程的运行原理 Python 中的协程 总结 协程 协程(co-routine,又称微线程)是一种多方协同的工作方式.当前执行者在某个时刻主动让出(yield)控制流,并记住自身当前的状态,以便在控制流返回时能从上次让出的位置恢复(resume)执行. 简而言之,协程的核心思想就在于执行者对控制流的 “主动让出” 和 “恢复”.相对于,线程此类的 “抢占式调度” 而言,协程是一种 “协作式调度” 方式. 协程的应用场景 抢占式调

  • python并发编程之多进程、多线程、异步和协程详解

    最近学习python并发,于是对多进程.多线程.异步和协程做了个总结. 一.多线程 多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行.即使是单CPU的计算机,也可以通过不停地在不同线程的指令间切换,从而造成多线程同时运行的效果. 多线程相当于一个并发(concunrrency)系统.并发系统一般同时执行多个任务.如果多个任务可以共享资源,特别是同时写入某个变量的时候,就需要解决同步的问题,比如多线程火车售票系统:两个指令,一个指令检查票是否卖完

  • Python全栈之协程详解

    目录 1. 线程队列 2. 进程池_线程池 3. 回调函数 4. 协程 总结: 1. 线程队列 # ### 线程队列 from queue import Queue """ put 存放 超出队列长度阻塞 get 获取 超出队列长度阻塞 put_nowait 存放,超出队列长度报错 get_nowait 获取,超出队列长度报错 """ # (1) Queue """先进先出,后进先出"""

  • go语言中的协程详解

    协程的特点 1.该任务的业务代码主动要求切换,即主动让出执行权限 2.发生了IO,导致执行阻塞(使用channel让协程阻塞) 与线程本质的不同 C#.java中我们执行多个线程,是通过时间片切换来进行的,要知道进行切换,程序需要保存上下文等信息,是比较消耗性能的 GO语言中的协程,没有上面这种切换,一定是通过协程主动放出权限,不是被动的. 例如: C# 中创建两个线程 可以看到1和2是交替执行的 Go语言中用协程实现一下 runtime.GOMAXPROCS(1) 这个结果就是 执行了1 在执

  • C++ boost库的安装过程详解

    Windows安装boost库 下载链接:https://www.boost.org/ 学习链接:https://theboostcpplibraries.com/ 1,下载解压,我的目录"C:\Program Files (x86)\Microsoft Visual Studio\2017" 2,以管理员身份运行"适用于 VS 2017 的 x64 本机工具命令提示" 3,执行以下命令进行编译: cd /d "C:\Program Files (x86)

  • C++ Boost PropertyTree解析INI文件详解

    目录 前言 什么是property_tree? 实现代码 前言 PropertyTree是一个非常牛叉的东西!虽然很小,但是,相当需要,相当重要!因为,很多的东西,我们不需要去开发,只需要去用就好了,这个东西的开发正的是极好极好的! 更重要的是,它来自大名鼎鼎的Boost库,这个库的重要性,已经是不言而喻了! property_tree是一个保存了多个属性的树形数据结构! 可以使用类似访问路径的方式问任意节点的属性,而且每个节点都可以用类似STL的风格遍历子节点. property_tree适合

  • C++ Boost Chrono实现计时码表流程详解

    目录 一.Boost.Chrono说明 二.示例代码 一.Boost.Chrono说明 库 Boost.Chrono 提供了多种时钟.例如,您可以获取当前时间,也可以测量流程中经过的时间. Boost.Chrono 的部分内容已添加到 C++11.如果您的开发环境支持 C++11,您可以访问头文件 chrono.xml 中定义的多个时钟.但是,C++11 不支持某些功能,例如用于测量 CPU 时间的时钟.此外,只有 Boost.Chrono 支持用户定义的时间输出格式. 二.示例代码 您可以通过

随机推荐