【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 }
菜鸟手记。