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是超時等待返回結果。異步
std::promise爲獲取線程函數中的某個值提供便利,在線程函數中給外面傳進來的promise賦值,當線程函數執行完成以後就能夠經過promis獲取該值了,值得注意的是取值是間接的經過promise內部提供的future來獲取的。它的基本用法:async
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保存的是一個函數。它的基本用法:函數
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來翻譯一下:this
小夥子說:我許諾會給你一個美好的將來等於c++11中"std::promise a std::future";
小夥子說:我會努力奮鬥爲你創造一個美好的將來等於c++11中"std::packaged_task a future";
姑娘說:我等着等於c++11中"future.get()/wait()";spa
小夥子兩句話的箇中差別,本身琢磨一下,這點差別也是std::promise和std::packaged_task的差別。現實中的山盟海誓靠不靠得住我不知道,可是c++11中的許諾和將來是必定可靠的,發起來了許諾就必定有將來。細想起來c++11標準的制定者選定的關鍵字真是貼切而有意思!好了,插科打諢到此了,如今言歸正傳,回過頭來講說std::async。線程
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已經幫你搞定一切了!翻譯
如今來看看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替代線程的建立,讓它成爲咱們作異步操做的首選。
若是你以爲這篇文章對你有用,能夠點一下推薦,謝謝。
c++11 boost技術交流羣:296561497,歡迎你們來交流技術。