promise

  1. 空模板
  2. 非 void 特化,用于在线程间交流对象
  3. void 特化,用于交流无状态事件

类模板 std::promise 提供存储值或异常的设施,之后通过 std::promise 对象所创建的 std::future 对象异步获得结果。注意 std::promise 只应当使用一次。

每个 promise 与共享状态关联,共享状态含有一些状态信息和可能仍未求值的结果,它求值为值(可能为 void )或求值为异常。 promise 可以对共享状态做三件事:

  • 使就绪: promise 存储结果或异常于共享状态。标记共享状态为就绪,并解除阻塞任何等待于与该共享状态关联的 future 上的线程。
  • 释放: promise 放弃其对共享状态的引用。若这是最后一个这种引用,则销毁共享状态。除非这是 std::async 所创建的未就绪的共享状态,否则此操作不阻塞。
  • 抛弃: promise 存储以 std::future_errc::broken_promise 为 error_code 的 std::future_error 类型异常,令共享状态为就绪,然后释放它。

promise 是 promise-future 交流通道的“推”端:存储值于共享状态的操作同步于(定义于 std::memory_order )任何在共享状态上等待的函数(如 std::future::get )的成功返回。其他情况下对共享状态的共时访问可能冲突:例如, std::shared_future::get 的多个调用方必须全都是只读,或提供外部同步

成员函数
(构造函数)  构造std::promise对象(公开成员函数)(析构函数)  析构std::promise对象(公开成员函数)operator=  赋值共享状态(公开成员函数)swap  交换二个 promise 对象(公开成员函数)
获取结果get_future  返回与承诺的结果关联的 future(公开成员函数)
设置结果set_value   设置结果为指定值(公开成员函数)set_value_at_thread_exit    设置结果为指定值,同时仅在线程退出时分发提醒(公开成员函数)set_exception  设置结果为指示异常(公开成员函数)set_exception_at_thread_exit   设置结果为指示异常,同时仅在线程退出时分发提醒(公开成员函数)
非成员函数std::swap(std::promise)(C++11)   特化std::swap算法(函数模板)
辅助类std::uses_allocator<std::promise>(C++11) 特化std::uses_allocator类型特征(类模板特化)
#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>void accumulate(std::vector<int>::iterator first,std::vector<int>::iterator last,std::promise<int> accumulate_promise)
{   //accumulate计算给定值 init 与给定范围 [first, last) 中元素的和int sum = std::accumulate(first, last, 0);accumulate_promise.set_value(sum);  // 提醒 future
}void do_work(std::promise<void> barrier)
{std::this_thread::sleep_for(std::chrono::seconds(1));barrier.set_value();
}int main()
{// 演示用 promise<int> 在线程间传递结果。std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };std::promise<int> accumulate_promise;std::future<int> accumulate_future = accumulate_promise.get_future();std::thread work_thread(accumulate, numbers.begin(), numbers.end(),std::move(accumulate_promise));// future::get() 将等待直至该 future 拥有合法结果并取得它// 无需在 get() 前调用 wait()//accumulate_future.wait();  // 等待结果std::cout << "result=" << accumulate_future.get() << '\n';work_thread.join();  // wait for thread completion// 演示用 promise<void> 在线程间对状态发信号std::promise<void> barrier;std::future<void> barrier_future = barrier.get_future();std::thread new_work_thread(do_work, std::move(barrier));barrier_future.wait();new_work_thread.join();
}

输出

result=21

future

类模板 std::future 提供访问异步操作结果的机制:

  • (通过 std::async 、 std::packaged_task 或 std::promise 创建的)异步操作能提供一个 std::future 对象给该异步操作的创建者。
  • 然后,异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值,则这些方法可能阻塞。
  • 异步操作准备好发送结果给创建者时,它能通过修改链接到创建者的 std::future 的共享状态(例如 std::promise::set_value )进行。

注意, std::future 所引用的共享状态不与另一异步返回对象共享(与 std::shared_future 相反)。

成员函数(构造函数)   构造 future 对象(公开成员函数)(析构函数)  析构 future 对象(公开成员函数)operator=  移动future对象(公开成员函数)share 从*this 转移共享状态给 shared_future并返回它(公开成员函数)
获取结果get 返回结果(公开成员函数)
状态valid 检查 future 是否拥有共享状态(公开成员函数)wait  等待结果变得可用(公开成员函数)wait_for    等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。(公开成员函数)wait_until   等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。(公开成员函数)
#include <iostream>
#include <future>
#include <thread>int main()
{// 来自 packaged_task 的 futurestd::packaged_task<int()> task([](){ return 7; }); // 包装函数std::future<int> f1 = task.get_future();  // 获取 futurestd::thread(std::move(task)).detach(); // 在线程上运行// 来自 async() 的 futurestd::future<int> f2 = std::async(std::launch::async, [](){ return 8; });// 来自 promise 的 futurestd::promise<int> p;std::future<int> f3 = p.get_future();std::thread( [&p]{ p.set_value_at_thread_exit(9); }).detach();std::cout << "Waiting..." << std::flush;f1.wait();f2.wait();f3.wait();std::cout << "Done!\nResults are: "<< f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
}
输出:Waiting...Done!
Results are: 7 8 9

shared_future

类模板 std::shared_future 提供访问异步操作结果的机制,类似 std::future ,除了允许多个线程等候同一共享状态。不同于仅可移动的 std::future (故只有一个实例能指代任何特定的异步结果),std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。

若每个线程通过其自身的 shared_future 对象副本访问,则从多个线程访问同一共享状态是安全的。
shared_future 可用于同时向多个线程发信,类似 std::condition_variable::notify_all()

成员函数(构造函数)   构造 future 对象(公开成员函数)(析构函数)  销毁future对象(公开成员函数)operator=    赋值内容(公开成员函数)
获取结果get 返回结果(公开成员函数)
状态valid 检查 future 是否拥有共享状态(公开成员函数)wait  等待结果变得可用(公开成员函数)wait_for    等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。(公开成员函数)wait_until   等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。(公开成员函数)
#include <iostream>
#include <future>
#include <chrono>int main()
{   std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;std::shared_future<void> ready_future(ready_promise.get_future());std::chrono::time_point<std::chrono::high_resolution_clock> start;auto fun1 = [&, ready_future]() -> std::chrono::duration<double, std::milli> {t1_ready_promise.set_value();ready_future.wait(); // 等待来自 main() 的信号return std::chrono::high_resolution_clock::now() - start;};auto fun2 = [&, ready_future]() -> std::chrono::duration<double, std::milli> {t2_ready_promise.set_value();ready_future.wait(); // 等待来自 main() 的信号return std::chrono::high_resolution_clock::now() - start;};auto result1 = std::async(std::launch::async, fun1);auto result2 = std::async(std::launch::async, fun2);// 等待线程变为就绪t1_ready_promise.get_future().wait();t2_ready_promise.get_future().wait();// 线程已就绪,开始时钟start = std::chrono::high_resolution_clock::now();// 向线程发信使之运行ready_promise.set_value();std::cout << "Thread 1 received the signal "<< result1.get().count() << " ms after start\n"<< "Thread 2 received the signal "<< result2.get().count() << " ms after start\n";
}

可能的输出:

Thread 1 received the signal 0.072 ms after start
Thread 2 received the signal 0.041 ms after start

packaged_task

类模板 std::packaged_task 包装任何可调用 (Callable) 目标(函数、 lambda 表达式、 bind 表达式或其他函数对象),使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

正如 std::function , std::packaged_task 是多态、具分配器的容器:可在堆上或以提供的分配器分配存储的可调用对象。

成员函数(构造函数)   构造任务对象(公开成员函数)(析构函数)    析构任务对象(公开成员函数)operator=    移动任务对象(公开成员函数)valid 检查任务对象是否拥有合法函数(公开成员函数)swap  交换二个任务对象(公开成员函数)
获取结果get_future  返回与承诺的结果关联的 std::future(公开成员函数)
执行operator()    执行函数(公开成员函数)make_ready_at_thread_exit   执行函数,并确保结果仅在一旦当前线程退出时就绪(公开成员函数)reset 重置状态,抛弃任何先前执行的存储结果(公开成员函数)
非成员函数std::swap(std::packaged_task)(C++11) 特化 std::swap 算法(函数模板)
辅助类
std::uses_allocator<std::packaged_task>   (C++11)(C++17 前)特化 std::uses_allocator 类型特征(类模板特化)
#include <iostream>
#include <cmath>
#include <thread>
#include <future>
#include <functional>// 避免对 std::pow 重载集消歧义的独有函数
int f(int x, int y) { return std::pow(x,y); }void task_lambda()
{std::packaged_task<int(int,int)> task([](int a, int b) {return std::pow(a, b); });std::future<int> result = task.get_future();task(2, 9);std::cout << "task_lambda:\t" << result.get() << '\n';
}void task_bind()
{std::packaged_task<int()> task(std::bind(f, 2, 11));std::future<int> result = task.get_future();task();std::cout << "task_bind:\t" << result.get() << '\n';
}void task_thread()
{std::packaged_task<int(int,int)> task(f);std::future<int> result = task.get_future();std::thread task_td(std::move(task), 2, 10);task_td.join();std::cout << "task_thread:\t" << result.get() << '\n';
}int main()
{task_lambda();task_bind();task_thread();
}

输出:

task_lambda: 512
task_bind:   2048
task_thread: 1024

async

函数模板 async 异步地运行函数 f (潜在地在可能是线程池一部分的分离线程中),并返回最终将保有该函数调用结果的 std::future 。

  1. 表现如同以 policy 为 std::launch::async | std::launch::deferred 调用 (2) 。换言之, f 可能执行于另一线程,或者它可能在查询产生的 std::future 的值时同步运行。
  2. 按照特定的执行策略 policy ,以参数 args 调用函数 f :
    • 若设置 async 标志(即 (policy & std::launch::async) != 0 ),则 async 在新的执行线程(初始化所有线程局域对象后)执行可调用对象 f ,如同产出 std::thread(std::forward(f), std::forward(args)…) ,除了若 f 返回值或抛出异常,则于可通过 async 返回给调用方的 std::future 访问的共享状态存储结果。
    • 若设置 deferred 标志(即 (policy & std::launch::deferred) != 0 ),则 async 以同 std::thread 构造函数的方式转换 f 与 args… ,但不产出新的执行线程。而是进行惰性求值:在 async 所返回的 std::future 上首次调用非定时等待函数,将导致在当前线程(不必是最初调用 std::async 的线程)中,以 args… (作为右值传递)的副本调用 f (亦作为右值)的副本。将结果或异常置于关联到该 future 的共享状态,然后才令它就绪。对同一 std::future 的所有后续访问都会立即返回结果。
    • 若 policy 中设置了 std::launch::async 和 std::launch::deferred 两个标志,则进行异步执行还是惰性求值取决于实现。
    • 若 policy 中未设置 std::launch::async 或 std::launch::deferred 或任何实现定义策略标志,则行为未定义。

任何情况下,对 std::async 的调用同步于(定义于 std::memory_order )对 f 的调用,且 f 的完成先序于令共享状态就绪。若选择 async 策略,则关联线程的完成同步于首个等待于共享状态上的函数的成功返回,或最后一个释放共享状态的函数的返回,两者的先到来者。若 std::decay::type 或 std::decay::type 中的每个类型不能从其对应的实参构造,则程序为谬构。

参数f  -   要调用的可调用 (Callable) 对象args...    -   传递给 f 的参数policy -   位掩码值,每个单独位控制允许的执行方法std::launch::async    运行新线程,以异步执行任务std::launch::deferred   调用方线程上首次请求其结果时执行任务(惰性求值)返回值指代此次调用 std::async 所创建的共享状态的 std::future 。
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
#include <string>
#include <mutex>std::mutex m;
struct X {void foo(int i, const std::string& str) {std::lock_guard<std::mutex> lk(m);std::cout << str << ' ' << i << '\n';}void bar(const std::string& str) {std::lock_guard<std::mutex> lk(m);std::cout << str << '\n';}int operator()(int i) {std::lock_guard<std::mutex> lk(m);std::cout << i << '\n';return i + 10;}
};template <typename RandomIt>
int parallel_sum(RandomIt beg, RandomIt end)
{auto len = end - beg;if (len < 1000)return std::accumulate(beg, end, 0);RandomIt mid = beg + len/2;auto handle = std::async(std::launch::async,parallel_sum<RandomIt>, mid, end);int sum = parallel_sum(beg, mid);return sum + handle.get();
}int main()
{std::vector<int> v(10000, 1);std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';X x;// 以默认策略调用 x.foo(42, "Hello") :// 可能同时打印 "Hello 42" 或延迟执行auto a1 = std::async(&X::foo, &x, 42, "Hello");// 以 deferred 策略调用 x.bar("world!")// 调用 a2.get() 或 a2.wait() 时打印 "world!"auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");// 以 async 策略调用 X()(43) :// 同时打印 "43"auto a3 = std::async(std::launch::async, X(), 43);a2.wait();                     // 打印 "world!"std::cout << a3.get() << '\n'; // 打印 "53"
} // 若 a1 在此点未完成,则 a1 的析构函数在此打印 "Hello 42"

可能的输出:

The sum is 10000
43
world!
53
Hello 42

C++ future相关推荐

  1. Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService

    一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...

  2. C++ 多线程:future 异步访问类(线程之间安全便捷的数据共享)

    文章目录 future前言 future描述 future类成员使用 总结 future前言 首先查看如下代码 #include <iostream> #include <threa ...

  3. C++11中std::future的使用

    C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...

  4. php解决 mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysq

    微信小程序开发交流qq群   173683895    承接微信小程序开发.扫码加微信. The mysql extension is deprecated and will be removed i ...

  5. 18-flutter的Future和FutureBuilder

    Future 表示接卸来某个时间的值或者错误,借助Future可以在flutter 总实现异步操作. 其本事是dart:async 包中的一个类,使用它的时候需要导入dart:async 包,Futu ...

  6. 深入浅出Rust Future - Part 1

    本文译自Rust futures: an uneducated, short and hopefully not boring tutorial - Part 1,时间:2018-12-02,译者: ...

  7. neutron CLI is deprecated and will be removed in the future. Use openstack CLI instead

    1.现象描述: 以前在测试环境中使用过icehouse版本,记得当时查看网络列表是使用neutron net-list,最近两天在测试openstack ocata的时候发现好多之前的命令都不能正常使 ...

  8. [面试]future模式

    Future模式 什么是future模式? 传统单线程环境下,调用函数是同步的,必须等待程序返回结果后,才可进行其他处理. Futrue模式下,调用方式改为异步. Futrue模式的核心在于:充分利用 ...

  9. 一次搞懂 Runnable、Callable、Future、FutureTask,不懂不要钱!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 一般创建线程只有两种方式,一种是继承Thread,一种是实 ...

  10. 笑了,面试官问我知不知道异步编程的Future。

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 荒腔走板 老规矩,先来一个简短的荒腔走板,给冰冷的技术文注 ...

最新文章

  1. Java 锁粗化与循环
  2. docker hub 国内镜像_Mac设置docker国内镜像源
  3. HDU 2001 计算两点间的距离
  4. boot lvm 分区_怎样使用kickstart创建逻辑卷管理(LVM)分区
  5. Android PM suspendresume
  6. CocoaPods 报错 [!] Error installing JSONModel
  7. 51单片机跑马灯c语言,51单片机——跑马灯详解(示例代码)
  8. 大地坐标系与经纬度转换(一):大地坐标系简介
  9. 在MAC终端下打开Finder
  10. camera理论基础和工作原理
  11. 泰坦尼克号数据_泰坦尼克号数据分析案例实战
  12. react组件设计原则_可靠React组件设计的7个准则之封装
  13. 关于Python爬取热搜的另一种方法
  14. 如何查看本地服务器名称
  15. 常见音频文件格式的特点。
  16. 拉格朗日粒子扩散模式FLEXPART,在大气污染溯源中的应用
  17. 综合素质计算机考点,教师资格综合素质考前必背知识点:基本能力
  18. LTE Paging
  19. 发生线下地推风波,水滴筹冤吗?
  20. Linux共享库编程方法,Linux共享库c

热门文章

  1. js 区分鼠标左右键点击
  2. C语言中的左移与右移
  3. http如何远程调用html页面,【Web】写个HTML页面去调试HTTP接口方便些
  4. Geomagic Wrap对齐
  5. Python之程序调试
  6. Linux启动命令代码
  7. Linux查看端口状态
  8. 微信的付费阅读功能,更适合什么玩家参与?
  9. android 覆盖安装 代码没有更新,android 无法覆盖安装软件
  10. 阻塞IO和非阻塞IO