【C++多線程】join()及注意


基礎  

  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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM