future
https://blog.csdn.net/fengbingchun/article/details/104115489?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1.pc_relevant_without_ctrlist&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1.pc_relevant_without_ctrlist&utm_relevant_index=1
# future
namespace std
{
enum class future_status {
ready, timeout, deferred };
enum class future_errc
{
broken_promise,
future_already_retrieved,
promise_already_satisfied,
no_state
};
class future_error;
const error_category& future_category();
error_code make_error_code(future_errc e);
error_condition make_error_condition(future_errc e);
template<typename ResultType>
class future;
template<typename ResultType>
class shared_future;
template<typename ResultType>
class promise;
template<typename FunctionSignature>
class packaged_task; // no definition provided
template<typename ResultType,typename ... Args>
class packaged_task<ResultType (Args...)>;
enum class launch {
async, deferred
};
template<typename FunctionType,typename ... Args>
future<result_of<FunctionType(Args...)>::type> async(FunctionType&& func,Args&& ... args);
template<typename FunctionType,typename ... Args>
future<result_of<FunctionType(Args...)>::type> async(std::launch policy,FunctionType&& func,Args&& ... args);
}
# std::future类型模板
future 封装的是一种访问异步操作的机制,我们看看官方文档怎么说说:
The class template std::future provides a mechanism to access the result of asynchronous operations: An asynchronous operation (created via std::async, std::packaged_task, or std::promise) can provide a std::future object to the creator of that asynchronous operation…
当在一个线程(creator)中创建(通过std::async,std::packaged_task 或者 std::promise)了一个异步操作(asynchronous operations,通常就是创建了一个新的线程,执行操作)的时候,这个异步操作会返回一个 future 对象给当前的线程,供其访问异步操作的状态,结果等等。
future 某种意义上表示的是一个异步操作,通过其成员函数我们能够获悉异步操作处于什么样的情况。可以通过 get 来等待异步操作结束并返回结果,是一个阻塞过程。wait 等待异步操作结束结束,也是一个阻塞过程。wait_for 是超时等待返回结果,wait_util 类似。
std::future_status status;
do
{
status = future.wait_for(std::chrono::seconds(1));
if (status == std::future_status::deferred)
{
std::cout << "deferred\n";
}
else if (status == std::future_status::timeout)
{
std::cout << "timeout\n";
}
else if (status == std::future_status::ready)
{
std::cout << "ready!\n";
}
}
while (status != std::future_status::ready);
# std::promise类型模板
std::promise类型模板提供设置异步结果的方法,这样其他线程就可以通过std::future实例来索引该结果。 专业的 future 提供商
struct MyData
{
int value;
float conf;
};
MyData data{0, 0.0f};
int main()
{
std::promise<MyData> dataPromise;
std::future<MyData> dataFuture = dataPromise.get_future();
std::thread producer(
[&] (std::promise<MyData> &data) -> void {
std::this_thread::sleep_for(std::chrono::seconds(1));
data.set_value({2, 1.0f});
},
std::ref(dataPromise)
);
std::thread consumer(
[&] (std::future<MyData> &data) -> void {
auto a = data.valid();
std::cout << a << std::endl;
auto res = data.get();
std::cout << res.value << "\t" << res.conf << std::endl;
auto b = data.valid();
std::cout << b << std::endl;
},
std::ref(dataFuture)
);
producer.join();
consumer.join();
return 0;
}
# std::packaged_task类型模板
packaged_task 是对一个任务的抽象,我们可以给其传递一个函数来完成其构造。 std::packaged_task包装任何可调用目标(函数、lambda表达式、bind表达式、函数对象)以便它可以被异步调用。它的返回值或抛出的异常被存储于能通过std::future对象访问的共享状态中。简言之,将一个普通的可调用函数对象转换为异步执行的任务。
通过packaged_task包装后,可以通过thread启动或者仿函数形式启动,其执行结果返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono>
#include <future>
using namespace std;
//普通函数
int Add(int x, int y)
{
return x + y;
}
void task_lambda()
{
//包装可调用目标时lambda
packaged_task<int(int,int)> task([](int a, int b){ return a + b;});
//仿函数形式,启动任务
task(2, 10);
//获取共享状态中的值,直到ready才能返回结果或者异常
future<int> result = task.get_future();
cout << "task_lambda :" << result.get() << "\n";
}
void task_thread()
{
//包装普通函数
std::packaged_task<int (int,int)> task(Add);
future<int> result = task.get_future();
//启动任务,非异步
task(4,8);
cout << "task_thread :" << result.get() << "\n";
//重置共享状态
task.reset();
result = task.get_future();
//通过线程启动任务,异步启动
thread td(move(task), 2, 10);
td.join();
//获取执行结果
cout << "task_thread :" << result.get() << "\n";
}
int main(int argc, char *argv[])
{
task_lambda();
task_thread();
return 0;
}
# std::async函数模板
std::async 大概的工作过程:先将异步操作用 std::packaged_task 包装起来,然后将异步操作的结果放到 std::promise 中,这个过程就是创造未来的过程。外面再通过 future.get/wait 来获取这个未来的结果。可以说,std::async 帮我们将 std::future、std::promise 和 std::packaged_task 三者结合了起来。
template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type>
async (launch policy, Fn&& fn, Args&&... args);
//该模板函数 async 异步地运行函数 fn 并返回最终将保存该函数调用结果的 std::future 中,其中policy策略有以下三种:
// 异步启动的策略
enum class launch {
// 异步启动,在调用std::async()时创建一个新的线程以异步调用函数,并返回future对象;
async = 0x1,
// 延迟启动,在调用std::async()时不创建线程,直到调用了future对象的get()或wait()方法时,才创建线程;
deferred = 0x2,
// 自动,函数在某一时刻自动选择策略,这取决于系统和库的实现,通常是优化系统中当前并发的可用性
any = async | deferred,
sync = deferred
};
// launch::async vs launch::deferred
#include <iostream> // std::cout
#include <future> // std::async, std::future, std::launch
#include <chrono> // std::chrono::milliseconds
#include <thread> // std::this_thread::sleep_for
void print_ten (char c, int ms) {
for (int i=0; i<10; ++i) {
std::this_thread::sleep_for (std::chrono::milliseconds(ms));
std::cout << c;
}
}
int main ()
{
std::cout << "with launch::async:\n";
std::future<void> foo = std::async (std::launch::async,print_ten,'*',100);
std::future<void> bar = std::async (std::launch::async,print_ten,'@',200);
// async "get" (wait for foo and bar to be ready):
foo.get();
bar.get();
std::cout << "\n\n";
std::cout << "with launch::deferred:\n";
foo = std::async (std::launch::deferred,print_ten,'*',100);
bar = std::async (std::launch::deferred,print_ten,'@',200);
// deferred "get" (perform the actual calls):
foo.get();
bar.get();
std::cout << '\n';
return 0;
}
# 关系
std::future是用于获取将来共享状态的运行结果或异常,相当于一个中间件,std::async 、std::promise、std::packaged_task都离不开它的帮助;
std::packaged_task用于包装可调用目标,以便异步执行任务;
std::promise用于设置共享状态的值,可以用于线程间交流,这个是比较特殊的。
std::async是最优雅地方式启动任务异步执行;在多数情况下,建议使用asyn开启异步任务,而不是使用packaged_task方式。