【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 }

 

posted @ 2020-06-06 16:30  Chen沉尘  阅读(12113)  评论(0编辑  收藏  举报