(C++11/14/17學習筆記):std::atomic續、std::async與std::thread對比
目錄
std::atomic續、std::async與std::thread對比
std::atomic續、std::async與std::thread對比
原子操作std::atomic續談
#include <iostream> #include <string> #include <thread> #include <mutex> #include <future> std::atomic<int> my_count{ 0 }; //封裝了一個int型別的物件(值),可以像操作一個int型別的變數一樣操作my_count void my_thread() //執行緒入口函式 { for (int i = 0; i < 1000000; i++) { // my_count++; //對應的是一個原子操作,不會被打斷 my_count += 1; } return; } int main() { std::thread threadObj1(my_thread); std::thread threadObj2(my_thread); threadObj1.join(); threadObj2.join(); std::cout << "兩個執行緒執行完畢,最終 my_count的值是" << my_count << std::endl; return 0; }
- 上述my_count++ ,及my_count += 1;都能保證是原子操作,結果正確,如果改為my_count = my_count + 1;則結果不正確:
- 一般atomic原子操作,針對++,--,+=,&=,|=,^=是支援的。其他的可能不支援。
std::async與std::thread對比
std::async引數詳述 ,async用來建立 一個非同步任務
#include <iostream> #include <string> #include <thread> #include <mutex> #include <future> using namespace std; int mythread() //執行緒入口函式 { cout << "mythread start" << "ThreadId = " << std::this_thread::get_id() << endl; //列印執行緒id cout << "mythread end" << "ThreadId = " << std::this_thread::get_id() << endl; //列印執行緒id return 100; } int main() { cout << "MianThreadID = " << std::this_thread::get_id() << endl; //列印主執行緒id std::future<int> ret = std::async(mythread); //建立執行緒並開始執行 //將future物件與async建立的執行緒繫結到一起,流程不卡在這裡,繼續執行 std::cout << ret.get() << std::endl; std::cout << "主執行緒結束" << std::endl; return 0; }
- 引數 std::launch::deferred【延遲呼叫】 ,以及std::launch::async【強制建立一個執行緒】
- 使用std::thread() 建立執行緒,如果系統資源緊張,那麼可能建立執行緒就會失敗,那麼執行std::thread()時整個程式可能崩潰。
- std::async()我們一般不叫建立執行緒(解釋async能夠建立執行緒),我們一般叫它建立 一個非同步任務。
- std::async和std::thread最明顯的不同,就是async有時候並不建立新執行緒。
- a)如果你用std::launch::deferred來呼叫async會怎麼樣?
- std::launch::deferred延遲呼叫,並且不建立新執行緒,延遲到future物件呼叫 get()或者 wait() 的時候才執行mythread()。
- 如果沒有呼叫get或者wait,那麼這個mythread()不會執行。
- b)std::launch::async:強制這個非同步任務在新執行緒上執行,這 意味著,系統必須要給我建立出新執行緒來執行mythread()。
- c)std::launch::async | std::launch::deferred,這裡這個 | :意味著呼叫async的行為可能是 “ 建立新執行緒並立即執行” 或者 沒有建立新執行緒並且延遲到呼叫 result.get()才開始執行任務入口函式,兩者居其一。
- d)不帶額外引數,只給async函式一個 入口函式名:
- 預設值應該是std::launch::async | std::launch::deferred;和c)效果完全一致。
- 換句話說:系統會自行決定是非同步(建立新執行緒)還是同步(不建立新執行緒)方式執行。
- 自行決定是啥意思?系統如何決定是 非同步(建立新執行緒)還是同步(不建立新執行緒)方式執行 ?
std::async和std::thread的區別(重點)
【std::thread】
- std::thread建立執行緒,如果系統資源緊張,建立執行緒失敗,那麼整個程式就會報異常崩潰(有脾氣)。
- std::thread建立執行緒的方式,如果執行緒返回值,你想拿到這個值也不容易。
【std::async】
- std::async建立非同步任務。可能建立也可能不建立執行緒。
- std::async呼叫方法很容易拿到執行緒入口函式的返回值。
【系統資源限制的影響】
- (1)如果用std::thread建立的執行緒太多,則可能建立失敗,系統報告異常,崩潰。
- (2)如果用std::async,一般就不會報異常不會崩潰,因為 如果系統資源緊張導致無法建立新執行緒的時候,std::async這種不加額外引數的呼叫 就不會建立新執行緒。而是後續誰呼叫了result.get()來請求結果,那麼這個非同步任務mythread就執行在執行這條get()語句所在的執行緒上。
- 如果你強制std::async一定 要建立新執行緒,那麼就必須使用 std::launch::async。承受的代價就是系統資源緊張時,程式崩潰。
- (3)經驗:一個程式裡,執行緒數量不宜超過100-200,原因是時間片的切換。
std::async不確定性問題的解決
- 不加額外引數的std::async呼叫 ,讓系統自行決定是否建立新執行緒。
- 問題焦點在於 std::future<int> result = std::async(mythread); 這種寫法寫法:
- 這個非同步任務到底有沒有被推遲執行,(即系統選擇的是std::launch::async還是std::launch::deferred方式)。
- std::future物件的wait_for函式(注意等待 0 秒進行判斷系統採用的策略):
std::future<int> result = std::async(mythread); //想判斷async到底有沒有建立新執行緒立即執行還是延遲(沒建立新執行緒)執行 std::future_status status = result.wait_for(0s); //(std::chrono::seconds(0)); if (status == std::future_status::deferred) { //執行緒被延遲執行了(系統資源緊張了,它給我採用std::launch::deferred策略了) cout << result.get() << endl; //這個時侯才去呼叫了mythread(); } else { //任務沒有被推遲,已經開始執行了被,執行緒被建立了; if (status == std::future_status::ready) { //執行緒成功返回 cout << "執行緒成功執行完畢並返回!" << endl; cout << result.get() << endl; } else if (status == std::future_status::timeout) { //超時執行緒還沒執行完 cout << "超時執行緒沒執行完!" << endl; cout << result.get() << endl; } }
總結
- 使用async,可能兩種情況:std::launch::async或者std::launch::deferred,可以通過 future的狀態來進行判斷,利用std::future物件的wait_for函式等待0秒(相當於執行到這裡就立即得到future物件的狀態)。
- 如果系統採用的是std::launch::deferred方式,那麼std::future物件就是std::launch::deferred狀態。
- 如果系統採用的是std::launch::async方式,那麼std::future物件有可能有兩種狀態,因為在新執行緒可能執行完也有可能沒有執行完,此時需要判斷std::future物件狀態是std::future_status::ready還是std::future_status::timeout。
相關文章
- `std::packaged_task`、`std::thread` 和 `std::async` 的區別與聯絡Packagethread
- c++11:std::boolalpha、std::noboolalphaC++
- c++11:std::bindC++
- std::bind與std::ref, why and how
- c++11:std::is_sameC++
- std::function用法學習Function
- std::async的使用總結
- 透徹理解C++11新特性:右值引用、std::move、std::forwardC++Forward
- profile對比std::regex與boost::regex的效能
- C++11併發程式設計:多執行緒std::threadC++程式設計執行緒thread
- std::vector 和 std::list 區別
- std::reserve和std::resize的區別
- C++11 執行緒同步介面std::condition_variable和std::future的簡單使用C++執行緒
- C++11中std::move、std::forward、左右值引用、移動建構函式的測試C++Forward函式
- Rust 標準庫中的 async/await (async-std)RustAI
- 詭異!std::bind in std::bind 編譯失敗編譯
- c++ std::vector 切記C++
- C++/C++11中std numeric limits的使用C++MIT
- 【C++併發實戰】(三) std::future和std::promiseC++Promise
- C++ 標準庫 std::set std::multiset swap()的使用C++
- std::count 函式函式
- ODRDMS_GOV_STDGo
- std::make_shared
- C++(std::vector)C++
- 智慧指標思想實踐(std::unique_ptr, std::shared_ptr)指標
- std-軟體過程與管理期末複習
- zend_std_read_property
- 理解 std::declval 和 decltype
- C++ 智慧指標詳解: std::unique_ptr 和 std::shared_ptrC++指標
- std-軟體測試期末複習
- 解決 /kaldi-trunk/tools 目錄下make安裝報錯需要支援 ISO C++ 2011 -std=c++11 or -std=gnu++11C++
- 【譯】對Rust中的std::io::Error的研究RustError
- c++11 執行緒間同步---利用std::condition_variable實現C++執行緒
- 實作中的 std::is_detected 和 Detection Idioms (C++17)C++
- std::string的find問題研究
- std::sort 錯誤"Expression : invalid operator <"Express
- `std::future`--非同步的優勢非同步
- C++(std::cout 處理 char*)C++