C++ future
promise
- 空模板
- 非 void 特化,用于在线程间交流对象
- 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 。
- 表现如同以 policy 为 std::launch::async | std::launch::deferred 调用 (2) 。换言之, f 可能执行于另一线程,或者它可能在查询产生的 std::future 的值时同步运行。
- 按照特定的执行策略 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相关推荐
- Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService
一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...
- C++ 多线程:future 异步访问类(线程之间安全便捷的数据共享)
文章目录 future前言 future描述 future类成员使用 总结 future前言 首先查看如下代码 #include <iostream> #include <threa ...
- C++11中std::future的使用
C++11中的std::future是一个模板类.std::future提供了一种用于访问异步操作结果的机制.std::future所引用的共享状态不能与任何其它异步返回的对象共享(与std::sha ...
- 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 ...
- 18-flutter的Future和FutureBuilder
Future 表示接卸来某个时间的值或者错误,借助Future可以在flutter 总实现异步操作. 其本事是dart:async 包中的一个类,使用它的时候需要导入dart:async 包,Futu ...
- 深入浅出Rust Future - Part 1
本文译自Rust futures: an uneducated, short and hopefully not boring tutorial - Part 1,时间:2018-12-02,译者: ...
- neutron CLI is deprecated and will be removed in the future. Use openstack CLI instead
1.现象描述: 以前在测试环境中使用过icehouse版本,记得当时查看网络列表是使用neutron net-list,最近两天在测试openstack ocata的时候发现好多之前的命令都不能正常使 ...
- [面试]future模式
Future模式 什么是future模式? 传统单线程环境下,调用函数是同步的,必须等待程序返回结果后,才可进行其他处理. Futrue模式下,调用方式改为异步. Futrue模式的核心在于:充分利用 ...
- 一次搞懂 Runnable、Callable、Future、FutureTask,不懂不要钱!
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 一般创建线程只有两种方式,一种是继承Thread,一种是实 ...
- 笑了,面试官问我知不知道异步编程的Future。
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 荒腔走板 老规矩,先来一个简短的荒腔走板,给冰冷的技术文注 ...
最新文章
- Java 锁粗化与循环
- docker hub 国内镜像_Mac设置docker国内镜像源
- HDU 2001 计算两点间的距离
- boot lvm 分区_怎样使用kickstart创建逻辑卷管理(LVM)分区
- Android PM suspendresume
- CocoaPods 报错 [!] Error installing JSONModel
- 51单片机跑马灯c语言,51单片机——跑马灯详解(示例代码)
- 大地坐标系与经纬度转换(一):大地坐标系简介
- 在MAC终端下打开Finder
- camera理论基础和工作原理
- 泰坦尼克号数据_泰坦尼克号数据分析案例实战
- react组件设计原则_可靠React组件设计的7个准则之封装
- 关于Python爬取热搜的另一种方法
- 如何查看本地服务器名称
- 常见音频文件格式的特点。
- 拉格朗日粒子扩散模式FLEXPART,在大气污染溯源中的应用
- 综合素质计算机考点,教师资格综合素质考前必背知识点:基本能力
- LTE Paging
- 发生线下地推风波,水滴筹冤吗?
- Linux共享库编程方法,Linux共享库c