什么是std::async
std::async()是一个接受回调(函数或函数对象)作为参数的函数模板,并有可能异步执行它们.
template<class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn, Args&&...args);
std::async返回一个std::future<T>,它存储由std::async()执行的函数对象返回的值。
函数期望的参数可以作为函数指针参数后面的参数传递给std::async()。
std::async中的第一个参数是启动策略,它控制std::async的异步行为,我们可以用三种不同的启动策略来创建std::async
·std::launch::async
保证异步行为,即传递函数将在单独的线程中执行
·std::launch::deferred
当其他线程调用get()来访问共享状态时,将调用非异步行为
·std::launch::async | std::launch::deferred
默认行为。有了这个启动策略,它可以异步运行或不运行,这取决于系统的负载,但我们无法控制它。
如果我们不指定一个启动策略,其行为将类似于std::launch::async | std::launch::deferred
本节我们将使用std::launch::async启动策略
我们可以在std::async传递任何回调,如:
·函数指针
·函数对象
·lambda表达式
为什么要用std::async
c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的:
void f(int n);
std::thread t(f, n + 1);
t.join();
但是线程毕竟是属于比较低层次的东西,有时候使用有些不便,比如我希望获取线程函数的返回结果的时候,我就不能直接通过 thread.join()
得到结果,这时就必须定义一个变量,在线程函数中去给这个变量赋值,然后join
,最后得到结果,这个过程是比较繁琐的。
c++11还提供了异步接口std::async
,通过这个异步接口可以很方便的获取线程函数的执行结果。std::async
会自动创建一个线程去调用 线程函数,它返回一个std::future
,这个future
中存储了线程函数返回的结果,当我们需要线程函数的结果时,直接从future
中获取,非 常方便。
但是我想说的是,其实std::async
给我们提供的便利可不仅仅是这一点,它首先解耦了线程的创建和执行,使得我们可以在需要的时候获取异步 操作的结果;其次它还提供了线程的创建策略(比如可以通过延迟加载的方式去创建线程),使得我们可以以多种方式去创建线程。
在介绍async
具体用法以及 为什么要用std::async
代替线程的创建之前,我想先说一说std::future
、std::promise
和 std::packaged_task
。
std::future、std::promise和std::packaged_task
std::async
是更高层次上的异步操作,使我们不用关注线程创建内部细节,就能方便的获取异步执行状态和结果,还可以指定线程创建策略,std::async
是为了 让用户的少费点脑子的,它让这三个对象默契的工作。大概的工作过程是这样的:std::async
先将异步操作用std::packaged_task
包装起来,然后将异步操作的结果放到std::promise
中,
下面介绍std::future、std::promise和std::packaged_task
std::future
std::future
是一个非常有用也很有意思的东西,简单说std::future
提供了一种访问异步操作结果的机制。从字面意思来理解, 它表示未来,我觉得这个名字非常贴切,因为一个异步操作我们是不可能马上就获取操作结果的,只能在未来某个时候获取,但是我们可以以同步等