基礎
join()函數的作用是讓主線程的等待該子線程完成,然后主線程再繼續執行。這種情況下,子線程可以安全的訪問主線程中的資源。子線程結束后由主線程負責回收子線程資源。一個子線程只能調用join()和detach()中的一個,且只允許調用一次。可以調用joinable()來判斷是否可以成功調用join()或detach()。
1 #include <thread> 2 #include <iostream> 3 4 using namespace std; 5 6 void test() 7 { 8 cout << "子線程開始執行!" << endl; 9 //do something 10 cout << "子線程執行完畢!" << endl; 11 } 12 int main() 13 { 14 cout << "主線程開始執行!" << endl; 15 thread t(test); 16 cout << "join()是否可調:" << boolalpha << t.joinable() << endl; 17 t.join(); //主線程等待子線程 18 cout << "join()是否可調:" << boolalpha << t.joinable() << endl; 19 cout << "主線程執行完畢!" << endl; 20 return 0; 21 }
注意
1、為了確保子線程程序在發送異常退出前完成,就需要對注意調用join()函數的位置,否則當主線發生異常而此時還沒有調用到join()函數,那么子線程隨主線程終止。解決方法是在異常處理中調用join()。
異常發生的情況,子線程沒有完成就隨主線程終止。
1 #include <thread> 2 #include <iostream> 3 4 using namespace std; 5 6 void func() 7 { 8 cout << "子線程func開始執行!" << endl; 9 //do something 10 int i = 100000; 11 while(i--) { } 12 cout << "子線程func執行結束!" << endl; 13 } 14 15 int main() 16 { 17 cout << "主線程main開始執行!" << endl; 18 thread t(func); 19 throw 123; 20 21 t.join(); 22 cout << "主線程main執行結束!" << endl; 23 return 0; 24 }
在異常處理中調用join()
1 #include <thread> 2 #include <iostream> 3 #include <cstdlib> //for rand() 4 5 using namespace std; 6 7 void func() 8 { 9 cout << "子線程func開始執行!" << endl; 10 //do something 11 int i = 100000; 12 while(i--) { } 13 cout << "子線程func執行結束!" << endl; 14 } 15 16 int main() 17 { 18 cout << "主線程main開始執行!" << endl; 19 thread t(func); 20 try 21 { 22 //do something 23 if (rand() % 7) //隨機拋出異常來模擬異常發生 24 { 25 throw 123; 26 } 27 } 28 catch(...) 29 { 30 //do something 31 t.join(); 32 abort(); //終止主線程 33 } 34 t.join(); //未發生異常時使用 35 cout << "主線程main執行結束!" << endl; 36 return 0; 37 }
2、為了應對忘記使用join()和選擇位置的問題,可以使用RAII機制來管理子線程,在RAII析構中調用join()。這樣在我根本不需要考慮join的位置問題,還是是否忘記的問題。但是這個方式在程序異常的情況下並不能保證主線程被終止時,子線程執行結束。因為程序因異常而終止時,如果沒有捕獲,對象的析構不會發生,只能由系統來回收資源。關於RAII:https://www.cnblogs.com/chen-cs/p/13027205.html
使用RAII在析構中調用join()
1 #include <thread> 2 #include <iostream> 3 4 using namespace std; 5 6 void func() 7 { 8 cout << "子線程func開始執行!" << endl; 9 //do something 10 int i = 100000 ; 11 while(i--) { } 12 cout << "子線程func執行結束!" << endl; 13 } 14 15 class RAII_thread 16 { 17 thread& t; 18 public: 19 explicit RAII_thread(thread& t_): t(t_) { } 20 ~RAII_thread(){ 21 if(t.joinable()) 22 t.join(); 23 } 24 RAII_thread(RAII_thread const&) = delete; 25 RAII_thread& operator=(RAII_thread const&) = delete; 26 }; 27 28 29 30 int main() 31 { 32 33 //確保異常發生時,子線程執行完畢的技巧2,使用RAII管理子線程 34 cout << "主線程main開始執行!" << endl; 35 thread t(func); 36 RAII_thread raii(t); 37 //do something 38 cout << "主線程main執行結束!" << endl; 39 return 0; 40 }