前面两讲《C++11 并发指南二(std::thread 详解)》,《C++11 并发指南三(std::mutex 详解)》分别介绍了 std::thread 和 std::mutex,相信读者对 C++11 中的多线程编程有了一个最基本的认识,本文将介绍 C++11 标准中 <future> 头文件里面的类和相关函数。

<future> 头文件中包含了以下几个类和函数:

  • Providers 类:std::promise, std::package_task
  • Futures 类:std::future, shared_future.
  • Providers 函数:std::async()
  • 其他类型:std::future_error, std::future_errc, std::future_status, std::launch.

std::promise 类介绍

promise 对象可以保存某一类型 T 的值,该值可被 future 对象读取(可能在另外一个线程中),因此 promise 也提供了一种线程同步的手段。在 promise 对象构造时可以和一个共享状态(通常是std::future)相关联,并可以在相关联的共享状态(std::future)上保存一个类型为 T 的值。

可以通过 get_future 来获取与该 promise 对象相关联的 future 对象,调用该函数之后,两个对象共享相同的共享状态(shared state)

  • promise 对象是异步 Provider,它可以在某一时刻设置共享状态的值。
  • future 对象可以异步返回共享状态的值,或者在必要的情况下阻塞调用者并等待共享状态标志变为 ready,然后才能获取共享状态的值。

下面以一个简单的例子来说明上述关系

#include <iostream>       // std::cout
#include <functional> // std::ref
#include <thread> // std::thread
#include <future> // std::promise, std::future void print_int(std::future<int>& fut) {
int x = fut.get(); // 获取共享状态的值.
std::cout << "value: " << x << '\n'; // 打印 value: 10.
} int main ()
{
std::promise<int> prom; // 生成一个 std::promise<int> 对象.
std::future<int> fut = prom.get_future(); // 和 future 关联.
std::thread t(print_int, std::ref(fut)); // 将 future 交给另外一个线程t.
prom.set_value(); // 设置共享状态的值, 此处和线程t保持同步.
t.join();
return ;
}

std::promise 构造函数

default (1)
promise();
with allocator (2)
template <class Alloc> promise (allocator_arg_t aa, const Alloc& alloc);
copy [deleted] (3)
promise (const promise&) = delete;
move (4)
promise (promise&& x) noexcept;
  1. 默认构造函数,初始化一个空的共享状态。
  2. 带自定义内存分配器的构造函数,与默认构造函数类似,但是使用自定义分配器来分配共享状态。
  3. 拷贝构造函数,被禁用。
  4. 移动构造函数。

另外,std::promise 的 operator= 没有拷贝语义,即 std::promise 普通的赋值操作被禁用,operator= 只有 move 语义,所以 std::promise 对象是禁止拷贝的。

例子:

#include <iostream>       // std::cout
#include <thread> // std::thread
#include <future> // std::promise, std::future std::promise<int> prom; void print_global_promise () {
std::future<int> fut = prom.get_future();
int x = fut.get();
std::cout << "value: " << x << '\n';
} int main ()
{
std::thread th1(print_global_promise);
prom.set_value();
th1.join(); prom = std::promise<int>(); // prom 被move赋值为一个新的 promise 对象. std::thread th2 (print_global_promise);
prom.set_value ();
th2.join(); return ;
}

std::promise::get_future 介绍

该函数返回一个与 promise 共享状态相关联的 future 返回的 future 对象可以访问由 promise 对象设置在共享状态上的值或者某个异常对象。只能从 promise 共享状态获取一个 future 对象。在调用该函数之后,promise 对象通常会在某个时间点准备好(设置一个值或者一个异常对象),如果不设置值或者异常,promise 对象在析构时会自动地设置一个 future_error 异常(broken_promise)来设置其自身的准备状态。上面的例子中已经提到了 get_future,此处不再重复。

std::promise::set_value 介绍

generic template (1)
void set_value (const T& val);
void set_value (T&& val);
specializations (2)
void promise<R&>::set_value (R& val);   // when T is a reference type (R&)
void promise<void>::set_value (void); // when T is void

设置共享状态的值,此后 promise 的共享状态标志变为 ready.

std::promise::set_exception 介绍

为 promise 设置异常,此后 promise 的共享状态变标志变为 ready,例子如下,线程1从终端接收一个整数,线程2将该整数打印出来,如果线程1接收一个非整数,则为 promise 设置一个异常(failbit) ,线程2 在std::future::get 是抛出该异常。

#include <iostream>       // std::cin, std::cout, std::ios
#include <functional> // std::ref
#include <thread> // std::thread
#include <future> // std::promise, std::future
#include <exception> // std::exception, std::current_exception void get_int(std::promise<int>& prom) {
int x;
std::cout << "Please, enter an integer value: ";
std::cin.exceptions (std::ios::failbit); // throw on failbit
try {
std::cin >> x; // sets failbit if input is not int
prom.set_value(x);
} catch (std::exception&) {
prom.set_exception(std::current_exception());
}
} void print_int(std::future<int>& fut) {
try {
int x = fut.get();
std::cout << "value: " << x << '\n';
} catch (std::exception& e) {
std::cout << "[exception caught: " << e.what() << "]\n";
}
} int main ()
{
std::promise<int> prom;
std::future<int> fut = prom.get_future(); std::thread th1(get_int, std::ref(prom));
std::thread th2(print_int, std::ref(fut)); th1.join();
th2.join();
return ;
}

std::promise::set_value_at_thread_exit 介绍

设置共享状态的值,但是不将共享状态的标志设置为 ready,当线程退出时该 promise 对象会自动设置为 ready。如果某个 std::future 对象与该 promise 对象的共享状态相关联,并且该 future 正在调用 get,则调用 get 的线程会被阻塞,当线程退出时,调用 future::get 的线程解除阻塞,同时 get 返回 set_value_at_thread_exit 所设置的值。注意,该函数已经设置了 promise 共享状态的值,如果在线程结束之前有其他设置或者修改共享状态的值的操作,则会抛出 future_error( promise_already_satisfied )。

std::promise::swap 介绍

交换 promise 的共享状态。

C++11 并发指南四(<future> 详解一 std::promise 介绍)的更多相关文章

  1. C++11 并发指南四(<future> 详解一 std::promise 介绍)(转)

    前面两讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread 和 std::m ...

  2. C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)

    上一讲<C++11 并发指南四(<future> 详解一 std::promise 介绍)>主要介绍了 <future> 头文件中的 std::promise 类, ...

  3. C++11 并发指南四(<future> 详解三 std::future & std::shared_future)

    上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...

  4. C++11 并发指南四(<future> 详解三 std::future & std::shared_future)(转)

    上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...

  5. C++11 并发指南三(Lock 详解)(转载)

    multithreading 多线程 C++11 C++11多线程基本使用 C++11 并发指南三(Lock 详解) 在 <C++11 并发指南三(std::mutex 详解)>一文中我们 ...

  6. C++11 并发指南三(Lock 详解)

    在 <C++11 并发指南三(std::mutex 详解)>一文中我们主要介绍了 C++11 标准中的互斥量(Mutex),并简单介绍了一下两种锁类型.本节将详细介绍一下 C++11 标准 ...

  7. 【C/C++开发】C++11 并发指南三(std::mutex 详解)

    本系列文章主要介绍 C++11 并发编程,计划分为 9 章介绍 C++11 的并发和多线程编程,分别如下: C++11 并发指南一(C++11 多线程初探)(本章计划 1-2 篇,已完成 1 篇) C ...

  8. C++11 并发指南系列

    本系列文章主要介绍 C++11 并发编程,计划分为 9 章介绍 C++11 的并发和多线程编程,分别如下: C++11 并发指南一(C++11 多线程初探)(本章计划 1-2 篇,已完成 1 篇) C ...

  9. C++11 并发指南系列(转)

    本系列文章主要介绍 C++11 并发编程,计划分为 9 章介绍 C++11 的并发和多线程编程,分别如下: C++11 并发指南一(C++11 多线程初探)(本章计划 1-2 篇,已完成 1 篇) C ...

随机推荐

  1. mac 上运行httpserver的问题

    如果你的系统是window 我建议你安装http-server 非常好用, 如果是mac,系统自带的就有httpserver 服务,没有必要在安装 按照我说的来操作 首先 sudo apachectl ...

  2. 如何在服务器上搭建svn

    svn现在依然是一个流行的版本控制工具,但是大多数的人员只会使用客户端,并且也知道可以进行权限控制, 那么今天,我们就来给大家梳理一下 1.如何搭建svn的服务器 2.如何进行svn的权限控制 === ...

  3. .Net Core(三)MVC Core

    MVC Core的改动感觉挺大的,需要的功能大多从Nuget安装,还内置了IOC,支持SelfHost方式运行等等. 一.项目结构的变化创建的新MVC项目的结构发生了变化,比如:静态文件需要统一放置到 ...

  4. Android Studio 通过一个登录功能介绍SQLite数据库的使用

    前言: SQLite简介:是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中.它是D.RichardHipp建立的公有领域项目.它的设计目标是嵌入式的,而且目前已经在 ...

  5. linux 开机自启动脚本

    在/etc/rc.local文件中添加自启动命令(其中一种方法) 1.案例,就用博主本人之前发的博文 “nginx + flask + uwsgi + centos + python3 搭建web项目 ...

  6. Spring Data JPA方法定义规范

    Spring Data Jpa方法定义的规则: (1)简单条件查询 简单条件查询:查询某一个实体类或者集合. 按照Spring Data的规范的规定,查询方法以find | read | get开头, ...

  7. 【HANA系列】SAP HANA XS使用服务器JavaScript Libraries详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用服务器 ...

  8. Linux 装机必备工具

    linux 装机必备工具:安装这些基本能满足日常需求. #!/usr/bin/env sh   echo "Env"       # vim   # tmux   # ssh   ...

  9. Django电商项目---完成商品主页显示day2

    利用DjangoAdmin初始化数据库 创建项目 python manage.py startapp df_goods 添加配置 manas/urls.py manas/settings.py 新创建 ...

  10. 【PAT】B1002 写出这个数

    思路: 1.以字符串形式输入数据,计算结果 2.使用sprintf将结果数字转换为字符串(将数字每一位分开) 3.分别输出字符每一位 1,笨方法,用的ifelse来判断输出 #include<s ...