我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++通信新特性协程详细介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++通信新特性协程详细介绍

一、关于协程

从 1.54.0 版本开始,Boost.Asio 支持协程。虽然您可以直接使用 Boost.Coroutine,但 Boost.Asio 中对协程的显式支持使得使用它们变得更加容易。

协程让您创建一个反映实际程序逻辑的结构。异步操作不会拆分函数,因为没有处理程序来定义异步操作完成时应该发生什么。程序可以使用顺序结构,而不是让处理程序相互调用。

二、协程的好处

考虑多任务协作的场景. 如果是线程的并发, 那么大家需要抢 CPU 用, 还需要条件变量/信号量或者上锁等技术, 来确保正确的线程正在工作.

如果在协程中, 大家就可以主动暂停自己, 多个任务互相协作. 这样可能就比大家一起抢 CPU 更高效一点, 因为你能够控制哪个协程用上 CPU.

一个例子:

生产者/消费者模型: 生产者生产完毕后, 暂停自己, 把控制流还给消费者. 消费者消费完毕后, resume 生产者, 生产者继续生产. 这样循环往复.

异步调用: 比如你要请求网络上的一个资源.

  • 发请求给协程
  • 协程收到请求以后, 发出请求. 协程暂停自己, 把控制权还回去.
  • 你继续做些别的事情. 比如发出下一个请求. 或者做一些计算.
  • 恢复这个协程, 拿到资源 (可能还要再等一等)

理想状态下, 4 可以直接用上资源, 这样就完全不浪费时间.

如果是同步的话:

  • 发请求给函数.
  • 函数收到请求以后, 等资源.
  • 等了很久, 资源到了, 把控制权还回去.

明显需要多等待一会儿. 如果需要发送上百个请求, 那显然是第一种异步调用快一点. (等待的过程中可以发送新的请求)

如果没有协程的话, 解决方案之一是使用多线程. 像这样:

  • 发请求给函数.
  • 函数在另外的线程等, 不阻塞你的线程.
  • 你继续做些别的事情. 比如发出下一个请求. 或者做一些计算.
  • 等到终于等到了, 他再想一些办法通知你.

然后通知的办法就有 promise 和回调这些办法.

三、协程得用法

我们照着 C++20 标准来看看怎么用协程. 用 g++, 版本 10.2 进行测试.

目前 C++20 标准只加入了协程的基本功能, 还没有直接能上手用的类. GCC 说会尽量与 clang MSVC 保持协程的 ABI 兼容, 同时和 libc++ 等保持库的兼容. 所以本文可能也适用于它们.

协程和主程序之间通过 promise 进行通信. promise 可以理解成一个管道, 协程和其调用方都能看得到.

以前的 std::async std::future 也是基于一种特殊的 promise 进行通信的, 就是 std::promise. 如果要使用协程, 则需要自己实现一个全新的 promise 类, 原理上是类似的.

四、与线程的区别

线程处于进程之中,协程处于线程之中,线程有系统内核调度,而协程有程序员自己调度。一个线程可以有多个协程,而且只要内存足够,一个线程中可以有任意多个协程;但某一时刻只能有一个协程在运行,多个协程分享该线程分配到的计算机资源。协程是追求极限性能和优美的代码结构的产物。

使用过程中需要包含#include <boost/coroutine2/all.hpp>,链接动态库:-lboost_coroutine -lboost_context。关于使用boost库错

协程有如下特点:

  1. 同其他数据类型一样,协程也是第一类(first-class)对象,可以被当参数传递等操作;
  2. 运行特点是挂起运行,离开协程,过后再进入,恢复运行;
  3. 具有对称和非对称的转移控制机制;
  4. 挂起前和恢复后本地变量的值是一致的;
  5. 有stackless和stackful两种类型

五、协程示例

示例 32.7。使用 Boost.Asio 的协程

#include <boost/asio/io_service.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <list>
#include <string>
#include <ctime>
using namespace boost::asio;
using namespace boost::asio::ip;
io_service ioservice;
tcp::endpoint tcp_endpoint{tcp::v4(), 2014};
tcp::acceptor tcp_acceptor{ioservice, tcp_endpoint};
std::list<tcp::socket> tcp_sockets;
void do_write(tcp::socket &tcp_socket, yield_context yield)
{
  std::time_t now = std::time(nullptr);
  std::string data = std::ctime(&now);
  async_write(tcp_socket, buffer(data), yield);
  tcp_socket.shutdown(tcp::socket::shutdown_send);
}
void do_accept(yield_context yield)
{
  for (int i = 0; i < 2; ++i)
  {
    tcp_sockets.emplace_back(ioservice);
    tcp_acceptor.async_accept(tcp_sockets.back(), yield);
    spawn(ioservice, [](yield_context yield)
      { do_write(tcp_sockets.back(), yield); });
  }
}
int main()
{
  tcp_acceptor.listen();
  spawn(ioservice, do_accept);
  ioservice.run();
}

调用 Boost.Asio 使用协程的函数是 boost::asio::spawn()。传递的第一个参数必须是 I/O 服务对象。第二个参数是将成为协程的函数。此函数必须接受 boost::asio::yield_context 类型的对象作为其唯一参数。它必须没有返回值。示例 32.7 使用 do_accept() 和 do_write() 作为协程。如果函数签名不同,例如 do_write() 的情况,您必须使用类似 std::bind 的适配器或 lambda 函数。

您可以将 boost::asio::yield_context 类型的对象而不是处理程序传递给异步函数。 do_accept() 将参数 yield 传递给 async_accept()。在 do_write() 中,yield 被传递给 async_write()。这些函数调用仍会启动异步操作,但在操作完成时不会调用任何处理程序。而是恢复启动异步操作的上下文。当这些异步操作完成时,程序会从中断的地方继续。

do_accept() 包含一个 for 循环。每次调用该函数时,都会将一个新套接字传递给 async_accept()。一旦客户端建立连接,do_write() 将作为协程调用,并带有 boost::asio::spawn() 以将当前时间发送给客户端。

for 循环可以很容易地看出程序在退出之前可以为两个客户端提供服务。由于该示例基于协程,因此可以在 for 循环中实现异步操作的重复执行。这提高了程序的可读性,因为您不必跟踪对处理程序的潜在调用来找出最后一个异步操作何时完成。如果时间服务器需要支持两个以上的客户端,则只需调整 for 循环。

到此这篇关于C++通信新特性协程详细介绍的文章就介绍到这了,更多相关C++协程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++通信新特性协程详细介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++通信新特性协程详细介绍

这篇文章主要给大家分享得是C++的特性协程Coroutine,下面文章内容我们将来具体介绍什么是协程,协程得好处等知识点,需要的朋友可以参考一下
2022-11-13

JDK8新特性详细介绍

函数式编程面向对象强调“一切皆对象”,如果想要做事情,必须要找到对象来做。函数式编程思想强调“做什么”,而不是“怎么做”。普通的开启线程// 匿名内部类对象Runnable task = new Runnable() { @Override pub
JDK8新特性详细介绍
2021-05-08

jdk1.5、1.6、1.7新特性详细介绍

JDK 1.5(也称为Java 5)的新特性包括:1. 泛型:引入了泛型,使得可以在编译时检查和强制类型安全的容器对象。2. 自动装箱和拆箱:自动将基本类型的值和对应的包装类对象进行相互转换。3. 增强for循环:简化了对数组和集合的遍历。
2023-08-25

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录