C++11 std::future and std::promise

在许多时候,我们会有这样的需求——即我们想要得到线程返回的值。

但是在C++11 多线程中我们注意到,std::thread对象会忽略顶层函数的返回值。

那问题来了,我们要怎么获得线程的返回值呢?

我们通过一个例子来说明如何实现这个需求。

假设我们的app会创建一个线程来压缩一个文件夹,该线程在压缩完文件夹后会返回压缩文件 *.zip 和这个zip文件的大小,我们现在就想获得这个线程的返回值。

有两种方法可以实现这个需求:

1. 传统的方法:在线程间共享指针

传递一个指针给压缩文件的线程,表示压缩文件的线程将会把值写入指针指向的内存空间。此时主线程将用条件变量等待值被写入,当压缩文件线程把值写入指针指定的内存后,将唤醒(signal)条件变量,然后主线程将被唤醒,然后从指针指向的内存中获取返回值。

为了实现获取一个返回值的需求,使用传统的方法,我们需要条件变量(condition variable), 互斥量(mutex),和指针三个对象。

如果假设,我们需要获得压缩线程里三个返回值,情况会变得更加复杂。

std::future就是来简化这个编程过程的

2. C++11的方法:使用std::futurestd::promise

人如其名,std::futurestd::promise对象就和他们的名字一样。这两个类在获取程序返回值的时候需要配合使用

std::future,是一个类模板,它存储着一个未来的值。

那问题来了,未来的值是什么鬼?

实际上一个std::future对象里存储着一个在未来会被赋值的变量,这个变量可以通过std::future提供的成员函数std::future::get()来得到。如果在这个变量被赋值之前就有别的线程试图通过std::future::get()获取这个变量,那么这个线程将会被阻塞到这个变量可以获取为止。

std::promise同样也是一个类模板,它的对象承诺会在未来设置变量(这个变量也就是std::future中的变量)。每一个std::promise对象都有一个与之关联的std::future对象。当std::promise设置值的时候,这个值就会赋给std::future中的对象了。


我们一步一步来看一下如何做

  1. 在主线程中创建std::promise对象
std::promise<int> promiseObj;

上面定义的promise对象还没有任何关联的值。但是它承诺某个线程将会设置与其关联的值,并且,当值被设置以后,可以通过与promise关联的std::future对象来获取该值。

假设我们的主线程将创建的std::promise对象传递给了压缩线程,那主线程要怎么知道压缩线程已经设置好了值呢?

答案就是使用 std::future对象

// main thread
std::future<int> futureObj = promiseObj.get_future();
int val = futureObj.get(); // compression thread
promiseObj.set_value(45);

compression thread未执行set_value()时,如果主线程调用了futureObj.get(),那么主线程将会被阻塞。

看整个时序图:

最终代码

#include<iostream>    //std::cout std::endl
#include<thread> //std::thread
#include<future> //std::future std::promise
#include<utility> //std::ref
#include<chrono> //std::chrono::seconds void initiazer(std::promise<int> &promiseObj){
std::cout << "Inside thread: " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
promiseObj.set_value(35);
} int main(){
std::promise<int> promiseObj;
std::future<int> futureObj = promiseObj.get_future();
std::thread th(initiazer, std::ref(promiseObj)); std::cout << futureObj.get() << std::endl; th.join();
return 0;
}

本文参考于C++11 Multithreading – Part 8: std::future , std::promise and Returning values from Thread,并做了适当修改

C++11获取线程的返回值的更多相关文章

  1. python使用threading获取线程函数返回值的实现方法

    python使用threading获取线程函数返回值的实现方法 这篇文章主要介绍了python使用threading获取线程函数返回值的实现方法,需要的朋友可以参考下 threading用于提供线程相 ...

  2. java 多线程 day10 获取线程的返回值 CallableAndFuture

    import java.util.Random;import java.util.concurrent.*; /** * Created by chengtao on 17/12/4. * * 获取线 ...

  3. python多线程获取子线程任务返回值

    今天想实现多线程更新资产信息,所以使用到了threading,但是我需要每个线程的返回值,这就需要我在threading.Thread的基础上进行封装 def auto_asset(node): re ...

  4. 无废话Android之activity的生命周期、activity的启动模式、activity横竖屏切换的生命周期、开启新的activity获取他的返回值、利用广播实现ip拨号、短信接收广播、短信监听器(6)

    1.activity的生命周期 这七个方法定义了Activity的完整生命周期.实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环: (1)Activity的完整生命周期 自第一次调用onCrea ...

  5. 统计文件种类数+获取子shell返回值的其它方法

    前言 只是作为一个shell的小小练习和日常统计用,瞎折腾的过程中也是摸到了获取子shell返回值的几种方法: 肯定还有别的方法,跟进程间的通信相关,希望你能提出建议和补充,谢谢~ 完整程序: #! ...

  6. 在Java 线程中返回值的用法

    http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread  有时在执行线程中需要在线程中返回一个值:常规中我们 ...

  7. web3调用call()方法获取不到返回值

    一.web3的call()获取不到返回值问题和解决方法 在彩票小合约中,遇到一个问题:合约中 有两个方法 第一个返回一个账户地址,没有使用到当前方法调用者信息: 第二个使用到了当前方法调用者信息 在w ...

  8. 利用SQLServer查询分析器获取存储过程的返回值,检查测试存储过程

    1.存储过程没有返回值的情况(即存储过程语句中没有return之类的语句)用方法 int count = ExecuteNonQuery(..)执行存储过程其返回值只有两种情况(1)如果通过查询分析器 ...

  9. python asyncio 获取协程返回值和使用callback

    1. 获取协程返回值,实质就是future中的task import asyncioimport timeasync def get_html(url): print("start get ...

随机推荐

  1. Andrew Ng机器学习课程笔记--week5(下)

    Neural Networks: Learning 内容较多,故分成上下两篇文章. 一.内容概要 Cost Function and Backpropagation Cost Function Bac ...

  2. python中列表 元组 字典 集合的区别

    列表 元组 字典 集合的区别是python面试中最常见的一个问题.这个问题虽然很基础,但确实能反映出面试者的基础水平. (1)列表 什么是列表呢?我觉得列表就是我们日常生活中经常见到的清单.比如,统计 ...

  3. Android-Error3:Error when loading the SDK

    解决方法: 用C:\android\sdk\tools中的devices.xml将出现错误的地方的devices.xml替换掉既可以了.

  4. java8新特性,使用流遍历集合

    在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda ...

  5. 安装oracle后登录时出现 ERROR: ORA-01031 insufficient privileges

    运行环境:在自己笔记本电脑(win10)上安装测试 操作系统版本:64位win8.1 Oracle版本:64位 oracle 11g 安装oracle 成功后//以管理员身份登录oracle 在cmd ...

  6. 银河麒麟操作系统U盘手动挂载,出现乱码

    使用银河麒麟操作系统,U盘手动挂载,U盘中中文字符显示为乱码??      对于银河麒麟操作系统的这一问题,可能是因为字符集的原因,需要在mount后加参数: sudo mount –o iochar ...

  7. 第1阶段——uboot分析之仿照bootm制作hello命令(7)

    仿照bootm命令生成来制作一个hello命令,功能:打印出hello,world!和参数值 1.点击New File ,创建cmd_hello.c将./common/cmd_bootm.c的头文件复 ...

  8. poj 1384完全背包

    题意:给出猪罐子的空质量和满质量,和n个硬币的价值和质量,求猪罐子刚好塞满的的最小价值. 思路:选择硬币,完全背包问题,塞满==初始化为无穷,求最小价值,min. 代码: #include<io ...

  9. Vue组件库的那些事儿,你都知道吗?

    前段时间一直在研究Vue组件库,终于在组内派上了用场.来给大家贡献一篇关于Vue组件库的相关知识.经验不多,如果有不合理的地方还请多多指出哦--- 回想一下,在你们公司或者你们小组是否有一个以上的项目 ...

  10. dreamweaver代码提示失效

    原文地址:dreamweaver代码提示失效作者:云中雁 2007-03-23 12:19:22|  分类: 编程手记 |  标签:web2.0  javascript   |字号大中小 订阅 吴庆民 ...