c++11中增长了线程,使得咱们能够很是方便的建立线程,它的基本用法是这样的:c++
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。express
std::future是一个很是有用也颇有意思的东西,简单说std::future提供了一种访问异步操做结果的机制。从字面意思来理解, 它表示将来,我以为这个名字很是贴切,由于一个异步操做咱们是不可能立刻就获取操做结果的,只能在将来某个时候获取,可是咱们能够以同步等待的方式来获取 结果,能够经过查询future的状态(future_status)来获取异步操做的结果。future_status有三种状态:promise
//查询future的状态 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);
获取future结果有三种方式:get、wait、wait_for,其中get等待异步操做结束并返回结果,wait只是等待异步操做完成,没有返回值,wait_for是超时等待返回结果。ruby
std::promise为获取线程函数中的某个值提供便利,在线程函数中给外面传进来的promise赋值,当线程函数执行完成以后就能够经过promis获取该值了,值得注意的是取值是间接的经过promise内部提供的future来获取的。它的基本用法:异步
std::promise<int> pr; std::thread t([](std::promise<int>& p){ p.set_value_at_thread_exit(9); },std::ref(pr)); std::future<int> f = pr.get_future(); auto r = f.get();
std::packaged_task它包装了一个可调用的目标(如function, lambda expression, bind expression, or another function object),以便异步调用,它和promise在某种程度上有点像,promise保存了一个共享状态的值,而packaged_task保存的是一 个函数。它的基本用法:async
std::packaged_task<int()> task([](){ return 7; }); std::thread t1(std::ref(task)); std::future<int> f1 = task.get_future(); auto r1 = f1.get();
至此, 咱们介绍了std::async相关的几个对象std::future、std::promise和std::packaged_task,其中 std::promise和std::packaged_task的结果最终都是经过其内部的future返回出来的,不知道读者有没有搞糊涂,为何有 这么多东西出来,他们之间的关系究竟是怎样的?且听我慢慢道来,std::future提供了一个访问异步操做结果的机制,它和线程是一个级别的属于低层 次的对象,在它之上高一层的是std::packaged_task和std::promise,他们内部都有future以便访问异步操做结 果,std::packaged_task包装的是一个异步操做,而std::promise包装的是一个值,都是为了方便异步操做的,由于有时我须要获 取线程中的某个值,这时就用std::promise,而有时我须要获一个异步操做的返回值,这时就用std::packaged_task。那 std::promise和std::packaged_task之间又是什么关系呢?说他们不要紧也关系,说他们有关系也有关系,都取决于你了,由于我 能够将一个异步操做的结果保存到std::promise中。若是读者还没搞清楚他们的关系的话,我就用更通俗的话来解释一下。好比,一个小伙子给一个姑 娘表白真心的时候也许会说:”我许诺 会 给你一个美好的将来“或者”我会努力奋斗为你创造一个美好的将来“。姑娘每每会说:”我等着“。如今我来将这三句话用c++11来翻译一下:函数
小伙子说:我许诺会给你一个美好的将来等于c++11中"std::promise a std::future";
小伙子说:我会努力奋斗为你创造一个美好的将来等于c++11中"std::packaged_task a future";
姑娘说:我等着等于c++11中"future.get()/wait()"; ui
小伙子两句话的个中差别,本身琢磨一下,这点差别也是std::promise和std::packaged_task的差别。现实中的山盟海 誓靠不靠得住我不知道,可是c++11中的许诺和将来是必定可靠的,发起来了许诺就必定有将来。细想起来c++11标准的制定者选定的关键字真是贴切而有 意思!好了,插科打诨到此了,如今言归正传,回过头来讲说std::async。this
std::async又是干啥的,已经有了td::future、std::promise和std::packaged_task,够多的 了,真的还要一个std::async来凑热闹吗,std::async表示很委屈:我不是来凑热闹的,我是来帮忙的。是的,std::async是为了 让用户的少费点脑子的,它让这三个对象默契的工做。大概的工做过程是这样的:std::async先将异步操做用std::packaged_task包 装起来,而后将异步操做的结果放到std::promise中,这个过程就是创造将来的过程。外面再经过future.get/wait来获取这个将来的 结果,怎么样,std::async真的是来帮忙的吧,你不用再想到底该怎么用std::future、std::promise和 std::packaged_task了,std::async已经帮你搞定一切了!spa
如今来看看std::async的原型async(std::launch::async | std::launch::deferred, f, args...),第一个参数是线程的建立策略,有两种策略,默认的策略是当即建立线程:
第二个参数是线程函数,第三个参数是线程函数的参数。
std::async基本用法:
std::future<int> f1 = std::async(std::launch::async, [](){
return 8;
});
cout<<f1.get()<<endl; //output: 8
std::future<int> f2 = std::async(std::launch::async, [](){
cout<<8<<endl;
});
f2.wait(); //output: 8
std::future<int> future = std::async(std::launch::async, [](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::cout << "waiting...\n";
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::cout << "result is " << future.get() << '\n';
可能的结果: waiting... timeout timeout ready! result is 8
std::async是更高层次上的异步操做,使咱们不用关注线程建立内部细节,就能方便的获取异步执行状态和结果,还能够指定线程建立策略,应该用std::async替代线程的建立,让它成为咱们作异步操做的首选。