C++11 异步操作future和aysnc

news2024/11/17 9:32:54

目录

C++11异步操作的4个接口

1. std::aysnc和std::future 

 std::future和std::aysnc的使用Demo

2. std::packaged_task

std::packaged_task的使用Demo

3. std::promise

std::promise的使用Demo

总结


C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

C++11异步操作的4个接口

std::future : 异步指向某个任务,然后通过future特性去获取任务函数的返回结果(把一个任务放入线程池运行,然后可以获取返回结果)
std::aysnc: 异步运行某个任务函数
std::packaged_task:将任务和feature绑定在一起的模板,是一种封装对任务的封装(线程池)
std::promise:承诺(线程1设置了某个值,通知另外的线程2)

1. std::aysncstd::future 

        std::future期待一个返回,从一个异步调用的角度来说,future更像是执行函数的返回值,C++标准库使用std::future为一次性事件建模,如果一个事件需要等待特定的一次性事件,那么这线程可以获取一个future对象来代表这个事件

        异步调用往往不知道何时返回,但是如果异步调用的过程需要同步,或者说后一个异步调用需要使用前一个异步调用的结果。这个时候就要用到future。把future当做异步函数的返回值。

        线程可以周期性的在这个future上等待一小段时间,检查future是否已经ready,如果没有,该线程可以先去做另一个任务,一旦future就绪,该future就无法复位(无法再次使用这个future等待这个事件),所以future代表的是一次性事件。

future的类型

在库的头文件中声明了两种future,唯一future(std::future)和共享future(std::shared_future)。

这两个是参照std::unique_ptr和std::shared_ptr设立的,前者的实例是仅有的一个指向其关联事件的实例,而后者可以有多个实例指向同一个关联事件,当事件就绪时,所有指向同一事件的std::shared_future实例会变成就绪。

future的使用

跟thread类似,async允许你通过将额外的参数添加到调用中,来将附加参数传递给函数。如果传入的函数指针是某个类的成员函数,则还需要将类对象指针传入(直接传入,传入指针,或者是std::ref封装)。

默认情况下,std::async是否启动一个新线程,或者在等待future时,任务是否同步运行都取决于你给的参数。这个参数为std::launch类型

  1. std::launch::async,表明函数会在创建的新线程上运行。
  2. std::launch::defered表明该函数会被延迟调用,直到在future上调用get()或者wait()为止。
  3. std::launch::sync = std::launch::defered,表明该函数会被延迟调用

    4.std::launch::any = std::launch::defered | std::launch::async,表明该函数会被延迟调用,调用时在新线程上运行

 std::future和std::aysnc的使用Demo

//future
#include <iostream>
#include <future>
#include <thread>
using namespace std;

int find_result_to_add()
{
    std::this_thread::sleep_for(std::chrono::seconds(5)); // 用来测试异步延迟的影响
    std::cout << "find_result_to_add" << std::endl;
    return 1 + 1;
}

int find_result_to_add2(int a, int b)
{
    std::this_thread::sleep_for(std::chrono::seconds(5)); // 用来测试异步延迟的影响
    return a + b;
}

void do_other_things()
{
    std::cout << "do_other_things" << std::endl;
//    std::this_thread::sleep_for(std::chrono::seconds(5));
}

int main()
{
//    std::future<T>                     std::async是异步线程
//三种方式
     std::future<int> result = std::async(std::launch::async, find_result_to_add);  //表明函数会在自己创建的线程上运行,不会阻塞当前线程
 //  std::future<decltype (find_result_to_add())> result = std::async(find_result_to_add);
 //  auto result = std::async(find_result_to_add);  // 推荐的写法
     do_other_things();
     std::cout << "result: " << result.get() << std::endl;  // 延迟是否有影响? 阻塞等待find_result_to_add返回值

//需要传递参数
//   std::future<decltype(find_result_to_add2(int, int))> result2 = std::async(find_result_to_add2, 10, 20); //错误
     std::future<decltype (find_result_to_add2(0, 0))> result2 = std::async(find_result_to_add2, 10, 20);
 //  auto result2 = std::async(find_result_to_add2, 10, 20);  // 推荐的写法
     std::cout << "result2: " << result2.get() << std::endl;  // 延迟是否有影响? 阻塞等待find_result_to_add2返回值

     std::cout << "main finish" << endl;
    return 0;
}

 

 

2. std::packaged_task

        如果说std::async和std::feature还是分开看的关系的话,那么std::packaged_task就是将任务和feature绑定在一起的模板,是一种封装对任务的封装。

        可以通过std::packaged_task对象获取任务相关联的feature,调用get_future()方法可以获得std::packaged_task对象绑定的函数的返回值类型的future。std::packaged_task的模板参数是函数签名。

std::packaged_task的使用Demo

//-package_task
#include <iostream>
#include <future>
#include <thread>

using namespace std;

int add(int a, int b, int c)
{
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "call add\n";
    return a + b + c;
}

void do_other_things()
{
    std::cout << "do_other_things" << std::endl;
}

int main()
{
    std::packaged_task<int(int, int, int)> task(add);  // 1. 封装任务,还没有运行
//    std::this_thread::sleep_for(std::chrono::seconds(2)); // 用来测试异步延迟的影响

    do_other_things();
    std::future<int> result = task.get_future(); // 这里运行吗?这里只是获取 future
    // 这里才真正运行
     task(1, 1, 2);   //必须要让任务执行,否则在get()获取future的值时会一直阻塞
     std::cout << "result:" << result.get() << std::endl;
     std::cout << "end" << std::endl;
    return 0;
}

 

3. std::promise

        std::promise提供了一种设置值的方式,它可以在这之后通过相关联的std::future对象进行读取。换种说法,之前已经说过std::future可以读取一个异步函数的返回值了,那么这个std::promise就提供一种方式手动让future就绪 

        线程在创建promise的同时会获得一个future,然后将promise传递给设置他的线程,当前线程则持有future,以便随时检查是否可以取值。 

std::promise的使用Demo

//promise
// std::promise和std::future配合,可以在线程之间传递数据。
#include <future>
#include <string>
#include <thread>
#include <iostream>
using namespace std;

void print1(std::promise<std::string>& p)
{
    std::cout << "print1 sleep" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    p.set_value("set string"); // 相当于返回future的结果
}

void print2(std::promise<int>& p)
{
    std::cout << "print2 sleep" << std::endl;
    p.set_value(1);
}

void do_some_other_things()
{
    std::cout << "do_some_other_things" << std::endl;
}

int main()
{
    std::cout << "main1 -------------" << std::endl;
    std::promise<std::string> promise;  // 注意类型:

    std::future<std::string> result = promise.get_future(); // future

    std::thread t(print1, std::ref(promise));  // 线程设置 传引用std::ref
    do_some_other_things();
    std::cout << "wait get result" << std::endl;
    std::cout <<"result " << result.get() << std::endl; // 在主线程等待 promise的返回 result set string
    t.join();

    std::cout << "\n\nmain2 -------------" << std::endl;
    std::promise<int> promise2;

    std::future<int> result2 = promise2.get_future();
    std::thread t2(print2, std::ref(promise2));
    do_some_other_things();
    std::cout << "result2 " << result2.get() << std::endl;
    t2.join();
    return 0;
}

总结

        future的表现为期望,当前线程持有future时,期望从future获取到想要的结果和返回,可以把future当做异步函数的返回值。

        promise是一个承诺,当线程创建了promise对象后,这个promise对象向线程承诺他必定会被人设置一个值,和promise相关联的future就是获取其返回的手段。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30239.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32F407高级定时器-死区时间研究-STM32CubeMX

距离上次写笔记&#xff0c;已经过去好长时间了 中间也折腾过不少东西&#xff0c;但是都没咋整理&#xff0c;主要是这中间都是在干活儿&#xff0c;不是自己想要研究的&#xff0c;也没想着要写。 从去年10月份开始想要学习FOC&#xff0c;10月份研究了一个月&#xff0c;到…

HTML5学习笔记(一)

XHTML&#xff0c;全称“EXtensible HyperText Mark-up Language&#xff08;扩展的超文本标记语言&#xff09;”&#xff0c;它是XML风格的HTML4.01&#xff0c;我们可以称之为更严格、更纯净的HTML4.01。 HTML语法书写比较松散&#xff0c;比较利于开发者编写。但是对于机器…

计算机的种类

文章目录计算机的种类一&#xff0c;模拟计算机二&#xff0c;数字计算机三&#xff0c;混合计算机计算机的种类 《计算机是什么》一节中讲到&#xff0c;根据不同计算机的尺寸&#xff0c;可以将计算机分为微型计算机、小型计算机、大型计算机、工作站和超级计算机5类。实际上…

string类(一)

目录 一、 string类对象的常见构造 二、string类对象的容量操作 2.1 size(返回字符串有效字符长度) 2.2 capacity(返回空间总大小) 2.3 reserve扩空间​编辑 2.4 resize初始化不会覆盖本来的空间​编辑 2.5 对于test_string7中每一句代码进行调试运行 三、string类对象的…

云中网络的隔离:GRE、VXLAN

对于云平台中的隔离问题&#xff0c;前面咱们用的策略一直都是 VLAN&#xff0c;但是我们也说过这种策略的问题&#xff0c;VLAN 只有 12 位&#xff0c;共 4096 个。当时设计的时候&#xff0c;看起来是够了&#xff0c;但是现在绝对不够用&#xff0c;怎么办呢&#xff1f; …

真的,Java并发编程基础入门看这个就够了

Java并发编程学习之02Java并发编程入门指南 真的&#xff0c;Java并发编程入门看这个就够了1. Java天生多线程2. Java启动多线程实现方式2.1 实现代码2.2 Thread和Runnable的区别2.3 start和run方法的区别3. Java如何停止线程呢3.1 已弃用方法3.2 推荐使用4. 守护线程5. 优先级…

JVM的GC算法CMS和G1

GC算法 -XX:UseSerialGC 新生代和老年代都使用串行收集器 串行收集器使用单线程并且是独占式的垃圾回收 -XX:UseParNewGC 新生代使用ParNew垃圾回收器&#xff0c;老年代使用串行收集器 ParNew是串行收集器的多线程版本&#xff0c;只工作在新生代&#xff08;可以见名知…

jmeter逻辑控制器和定时器

常用逻辑控制器和定时器一、认识逻辑控制器一、作用&#xff1a;⼀个事务会包含并请求二、常见逻辑控制器介绍1、simple controller2、recorder controller3、loop controller4、random controller5、if controller6、module/include controller7、transaction controller三、J…

A Survey on Bias and Fairness in Machine Learning 阅读笔记

论文链接 Section 1 引言 1. In the context of decision-making, fairness is the absence of any prejudice or favoritism toward an individual or group based on their inherent or acquired characteristics. 公平是指基于个人或群体的固有或后天特征而对其没有任何偏…

【sfu】rtc 入口

rtc 入口 入口是 rtc adpter 类。 准备 call模块的所有资源 通过call模块使用webrtc内置 各类 rtcadpter的创建类rtcadpterfactory 是外部创建的 创建adapterfactory的外部类是peerconnection adapter_factory_ = std::move(std::make_unique

融云全球社交泛娱乐洞察,互联网社交换挡期的「社区产品」机遇

一切应用都将社交化。关注【融云全球互联网通信云】回复【融云】抽取高颜值大容量高端可乐保温杯哦~ 融入社交能力&#xff0c;创造增长奇迹。激活用户在不同场景的社交需求&#xff0c;让应用焕发新的生命力&#xff0c;也让“社交X”成为出海最大的浪。 《2022 社交泛娱乐出…

编译原理--基本块的划分

基本块的划分原则有4条 初始语句作为第一个基本块的入口遇到标号类语句&#xff0c;结束当前基本块&#xff0c;标号作为新基本块的入口&#xff08;标号不在当前基本块中&#xff0c;而是划到下一个基本块&#xff09;遇到转移类语句时&#xff0c;结束当前当前基本块&#x…

Java反序列化之CommonsCollections(CC1)分析篇

文章目录前言一、过程分析 1.入口点---危险方法InvokerTransformer.transform() 2.触发危险函数TransformedMap.checkSetValue() 3.AnnotationInvocationHandler类 4.ChainedTransformer类 5.ChainedTransformer类前言 本文包括&#xff1a;Java反序列化之CommonsCol…

3DMAX一键生成螺母和螺栓插件使用教程

插件介绍 3DMAX一键生成螺母和螺栓插件&#xff0c;用于创建精缰化的螺母和螺栓模型。这些模型是逼真的&#xff0c;只需单击一下即可生成。有许多参数可以定制模型的外观或尺寸。 主要功能 单击创建螺母、螺栓和垫圈在螺栓顶部创建文本标记&#xff08;商标&#xff09;直径…

关于不同长度PEG的丙炔:Pyrene-PEG2/PEG3/PEG4/PEG5-propargyl,1817735-33-3

Pyrene-PEG2-Propargyl中芘用于蛋白质构象和相互作用研究中的荧光探针&#xff0c;降冰片烯很容易与叠氮化物和四嗪反应&#xff0c;可用于用荧光团和功能分子标记细胞&#xff0c;亲水性 PEG 间隔臂可以增加水溶性。包括PEG2、PEG3、PEG4、PEG5等不同长度的PEG。 1、Pyrene-PE…

大数据:Shell的操作

文章目录HDFS常用命令一、创建目录1、创建单层目录2、创建多层目录查看目录三、上传本地文件到HDFS四、查看文件内容五、下载HDFS文件到本地六、删除HDFS文件七、删除HDFS目录HDFS常用命令 启动Hadoop集群命令&#xff1a;start-all.sh 一、创建目录 1、创建单层目录 命令…

Spring Boot Auto-Configuration

Spring 自定义Auto-Configuration Spring Boot 可以根据classpath中依赖关系自动装配应用程序。通过自动装配机制&#xff0c;可以使开发更快、更简单。今天&#xff0c;学习下如何在Spring Boot 中创建自定义 auto-configuration。 代码运行环境 JDK17MYSQL8源码地址 Mave…

[附源码]Python计算机毕业设计大学生心理健康管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

VSCODE编译阿里云HaaS程序时遇到Win32file找不到错误怎么办?

摘要&#xff1a;本文介绍DLL load failed while importing win32file&#xff1a;找不到指定的程序&#xff0c;这个错误的解决方法。使用vscode拉取阿里云HaaS物联网开发案例代码时&#xff0c;可能会遇到编译出错的情况&#xff0c;可能会遇到一些意外的问题&#xff0c;并非…

通过Native Memory Tracking查JVM的线程内存使用(线上JVM排障之九)

很多时候会面对线上内存使用很多,特别是本地内存怎么用的说不太清,就是每一块内存总和和总的Java线程占用内存不匹配。 很多时候如果dump出来内存也没有太大的作用,因为本地内存是看不到。本地内存有很多是线程占用的空间。 以下图为例,这是一个线上的服务的JVM各块内存使…