• async
  • future
  • packaged_task
  • promise

async

std:async 是个函数,用来启动一个异步任务,启动起来一个异步任务之后,返回一个std::futre对象,启动一个异步任务,就是自动创建一个线程并开始执行对应的线程入口函数,它返回一个std::future对象,这个std::future对象里面就含有线程入口函数返回的结果。可以通过调用future对象的成员函数get来获取结果。

"future" 提供了一种访问异步操作结果的机制,程序运行的结果,可能没有办法马上拿到。可能需要一定时间才能返回结果。在线程执行完毕的时候,就能够拿到结果。所以大家这么理解,future里会保存一个值。

例子:

引入一个头文件

#include<future>

 需要执行的函数,线程入口函数

int mythread()
{
cout << "my thread start, and thread id is " << std::this_thread::get_id() <<endl;
std::chrono::milliseconds dura(500);
std::this_thread::sleep_for(dura);
cout << "my thread end, and thread id is " << std::this_thread::get_id() <<endl; return 5; }

  在main中:

	cout << "Main Thread End!!! " <<std::this_thread::get_id() <<endl;

	std::future<int> result = std::async(mythread);

	cout << "continue..." << endl;

	int def = 0;
def = 0;
cout << result.get() << endl;
cout << "Main thread end" << endl;

  当执行到get的时候,系统会卡在这里,一直等待线程执行完毕。线程执行完毕之后,返回。future里有个标记,标记当前的线程已经执行完毕,流程才能继续往下走。绑定关系,future和async创建的线程绑定到一起,一定要等待线程执行完了,程序才能往下执行。

future

get函数不拿到 future的返回值,就卡在这里等待拿值,必须要保证和future有关的函数一定要有返回值。

future中还有一个wait(),等待线程返回,本身并不返回结果。 join();

程序中如果同时写多个get函数,那么就会报错,get只能调用一次!

在std::thread 用类的成员函数来作为线程的入口函数,用async也能用类的成员函数来作为线程的入口函数。

std::future<int> result = std::async(&class::method, &obj, para1)

 从第三个参数开始,才是成员函数对应的参数。第二个参数是一个对象引用,才能保证线程里面用的是同一个对象,线程里面当执行函数的时候仍然对应的是那个对象。

std::future<int> result = std::async(std::launch::deferred, &class::method, &obj, para1);

std::future<int> result = std::async(std::launch::async, &class::method, &obj, para1);

  

如果新建了future对象之后,不用get()和wait(),线程依然会运行,线程运行结束后,程序退出。

get()成员函数等待线程执行结束后返回结果,我们通过额外向std::async()传递一个参数,该参数类型是std::launch类型(枚举类型)来达到一些特殊的目的。

a)std::launch::deferred:表示线程入口函数调用被延迟到std::future的wait()或者get()函数调用时才执行。实际上线程根本没有被创建。

b) std::launch::async,在调用的时候就开始创建线程,不会等到get().

两个标记不能一起使用,用的时候必须要搞明白这些标记的含义。

packaged_task

std::packaged_task:打包任务,或者说将任务包装起来,这也是一个类模板。模板参数是各种可调用参数,通过packaged_task可以把各种可调用对象包装起来,方便将来作为线程入口函数作为调用。

在main函数中,相当于包装了一个函数,<int(int)> 返回值(参数),实参就是入口函数,可调用对象。我们

std::packaged_task<int(int)>  mypt(mythread);

把函数mythread通过如下写法调用:

std::thread t1(std::ref(mypt), 1);

 只不过线程创建方法是包装起来的线程入口函数,线程直接开始执行,第二个参数1,作为线程入口函数的参数,作为mythread的入口参数。通过future取结果

std::future<int> result = mypt.get_future();

  只要绑定之后,future里面保存的就是mypt里面的值。std::future对象里包含有线程入口函数的返回结果,这里result保存mythread。

packaged_task 包装起来的可调用对象还可以直接调用。

promise

std::promise这个也是一个类模板,作用是能够在某个线程中给它赋值,然后把这个值取出来。在线程中进行一个很复杂的运算,然后拿到运算结果。

void mythread(std::promise<int> &tmp, int calc);

  可以在函数中做一系列复杂的操作,然后做其他运算,整整花费了5s,休息了一定时间,结果可以保存下来,然后

int result = calc;
tmp.set_value(result); //将结果保存并返回

  结果保存到了tmp这个对象中,在main中声明一个std::promise对象,可以保存这个值,保存的值为int类型

std::promise<int> myprom;
std::thread t1(mythread, std::ref(myprom), para); //然后等线程执行完
t1.join();

  获取结果可以用到其他线程中去。

std::future<int> fu1 = myprom.get_future(); //promise和future绑定用于获取线程返回值

  如果前面join了后面get能够马上拿到这个值。

auto result = fu1.get();

  

C++并发与多线程学习笔记--async、future、packaged_task、promise的更多相关文章

  1. C++并发与多线程学习笔记--future成员函数、shared_future、atomic

    std::future的其他成员函数 std::shared_future 原子操作.概念.基本用法 多线程主要是为了执行某个函数,本文的函数的例子,采用如下写法 int mythread() { c ...

  2. C++并发与多线程学习笔记--atomic

    std::atomic std::async std::atomic 一般atomic原子操作,针对++,--,+=,^=是支持的,其他结果可能不支持. 注意 std::atomic<int&g ...

  3. C++并发与多线程学习笔记--基本概念和实现

    基本概念 并发 可执行程序.进程.线程 学习心得 并发的实现方法 多进程并发 多线程并发 总结 C++标准库 基本概念 (并发.进程.线程)区分C++初级编程和中高级编程 并发 两个或者更多的任务同时 ...

  4. C++并发与多线程学习笔记--互斥量、用法、死锁概念

    互斥量(mutex)的基本概念 互斥量的用法 lock(), unlock() std::lock_guard类模板 死锁 死锁演示 死锁的一般解决方案 std::lock()函数模板 std::lo ...

  5. C++并发与多线程学习笔记--单例设计模式、共享数据分析

    设计模式 共享数据分析 call_once 设计模式 开发程序中的一些特殊写法,这些写法和常规写法不一样,但是程序灵活,维护起来方便,别人接管起来,阅读代码的时候都会很痛苦.用设计模式理念写出来的代码 ...

  6. C++并发与多线程学习笔记--多线程数据共享问题

    创建和等待多个线程 数据和共享问题分析 只读的数据 有读有写 其他案例 共享数据的保护案例代码 创建和等待多个线程 服务端后台开发就需要多个线程执行不同的任务.不同的线程执行不同任务,并返回执行结果. ...

  7. C++并发与多线程学习笔记--参数传递详解

    传递临时对象 陷阱 总结 临时对象作为线程参数 线程id的概念 临时对象构造时的抓捕 成员函数指针做线程函数 传递临时对象作为线程参数 创建的工作线程不止一个,线程根据编号来确定工作内容.每个线程都需 ...

  8. C++并发与多线程学习笔记--线程之间调度

    condition_variable wait() notify_one notify_all condition_variable 条件变量的实际用途: 比如有两个线程A和B,在线程A中等待一个条件 ...

  9. C++并发与多线程学习笔记--unique_lock详解

    unique_lock 取代lock_quard unique_lock 的第二个参数 std::adopt_lock std::try_to_lock std::defer_lock unique_ ...

随机推荐

  1. svn conflict & svn cleanup

    svn conflict & svn cleanup OK $ svn --help $ svn cleanup Tree Conflicts https://tortoisesvn.net/ ...

  2. PAUL ADAMS ARCHITECT:澳洲房贷最低利率来袭

    11月3日澳洲储备银行宣布将官方现金利率从0.25%降至0.1%,破历史最低纪录.此次澳洲储备银行降息的目的主要是为了刺激经济走出全球经济危机引发的衰退.据了解,这已经是澳洲今年第三次降息,也是自20 ...

  3. linux DRM 之 GEM 笔记

    原文链接:https://www.cnblogs.com/yaongtime/p/14418357.html 在GPU上的各类操作中涉及到多种.多个buffer的使用. 通常我们GPU是通过图像API ...

  4. yaml配置和ini配置的数据源配置和数据获取

    1.前言 关于yaml和ini的相关理论暂不做记录,不影响代码编写,百度即可. 2.关于配置文件的选择 yaml 和 ini 都使用过, 但是yaml更符合人类使用,已要弃用ini,后期各项目均采用y ...

  5. DisplayFormat属性

    DataFormatString="{0:格式字符串}" 在DataFormatString 中的 {0} 表示数据本身,而在冒号后面的格式字符串代表所们希望数据显示的格式: 数字 ...

  6. 微信小程序(八)-项目实例(原生框架 MINA转云开发)==03-云开发-数据库

    云数据库 云数据库开发文档:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database.html 1.新建云数据库( ...

  7. JSON的stringify和parse方法

    一.JSON.parse() 方法用于将一个 JSON 字符串转换为对象. 以下代码为将字符串解析为对象,然后再赋值给对象 //页面初始化完成加载,option是传递的参数 onLoad: funct ...

  8. Virtual DOM 简直就是挥霍

    彻底澄清"Virtual DOM 飞快"的神话. 注意:原文发表于2018-12-27,随着框架不断演进,部分内容可能已不适用. 近年来,如果你有使用过 JavaScript 框架 ...

  9. 痞子衡嵌入式:盘点国内RISC-V内核MCU厂商(2020年发布产品)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是国内RISC-V内核MCU厂商(2020). 虽然RISC-V风潮已经吹了好几年,但2019年才是其真正进入主流市场的元年,最近国内大量 ...

  10. 在C#的WPF程序使用XAML实现画线

    在WPF中画直线.新建WPF应用程序,使用XAML画直线.使用X1.Y1两个属性可以设置直线的起点坐标,X2.Y2两个属性则可以设置直线的终点坐标.控制起点/终点坐标就可以实现平行.交错等效果.Str ...