C++11多執行緒程式設計 第二章: join 和 detach 執行緒
C++11 Multithreading – Part 2: Joining and Detaching Threads
Varun January 21, 2015 C++11 Multithreading – Part 2: Joining and Detaching Threads2018-08-18T15:11:46+00:00C++ 11, c++11 Threads, std::thread
In this article we will discuss about joining and detaching of std::thread.
Joining Threads with std::thread::join()
Once a thread is started then another thread can wait for this new thread to finish. For this another need need to call join() function on the std::thread object i.e.
1 2 3 4 5 |
std::thread th(funcPtr);
// Some Code
th.join(); |
Let’s see an example ,
Suppose Main Thread has to start 10 Worker Threads and after starting all these threads, main function will wait for them to finish. After joining all the threads main function will continue,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <iostream> #include <thread> #include <algorithm> class WorkerThread { public: void operator()() { std::cout<<"Worker Thread "<<std::this_thread::get_id()<<" is Executing"<<std::endl; } }; int main() { std::vector<std::thread> threadList; for(int i = 0; i < 10; i++) { threadList.push_back( std::thread( WorkerThread() ) ); } // Now wait for all the worker thread to finish i.e. // Call join() function on each of the std::thread object std::cout<<"wait for all the worker thread to finish"<<std::endl; std::for_each(threadList.begin(),threadList.end(), std::mem_fn(&std::thread::join)); std::cout<<"Exiting from Main Thread"<<std::endl; return 0; } |
Detaching Threads using std::thread::detach()
Detached threads are also called daemon / Background threads. To detach a thread we need to call std::detach() function on std::thread object i.e.
1 2 |
std::thread th(funcPtr); th.detach(); |
After calling detach(), std::thread object is no longer associated with the actual thread of execution.
Be careful with calling detach() and join() on Thread Handles
Case 1: Never call join() or detach() on std::thread object with no associated executing thread
Case 1: 呼叫join或detach前, 先判斷是否joinable
1 2 3 |
std::thread threadObj( (WorkerThread()) ); threadObj.join(); threadObj.join(); // It will cause Program to Terminate |
When a join() function is called on an thread object, then when this join(0 returns then that std::thread object has no associated thread with it. In case again join() function is called on such object then it will cause the program to Terminate.
Similarly calling detach() makes the std::thread object not linked with any thread function. In that case calling detach(0 function twice on an std::thread object will cause the program to terminate.
1 2 3 |
std::thread threadObj( (WorkerThread()) ); threadObj.detach(); threadObj.detach(); // It will cause Program to Terminate |
Therefore, before calling join() or detach() we should check if thread is join-able every time i.e.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
std::thread threadObj( (WorkerThread()) ); if(threadObj.joinable()) { std::cout<<"Detaching Thread "<<std::endl; threadObj.detach(); } if(threadObj.joinable()) { std::cout<<"Detaching Thread "<<std::endl; threadObj.detach(); }
std::thread threadObj2( (WorkerThread()) ); if(threadObj2.joinable()) { std::cout<<"Joining Thread "<<std::endl; threadObj2.join(); } if(threadObj2.joinable()) { std::cout<<"Joining Thread "<<std::endl; threadObj2.join(); } |
Case 2 : Never forget to call either join or detach on a std::thread object with associated executing thread
Case 2: join或detach你最少呼叫一個
If neither join or detach is called with a std::thread object that has associated executing thread then during that object’s destruct-or it will terminate the program.
Because inside the destruct-or it checks if Thread is Still Join-able then Terminate the program i.e.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> #include <thread> #include <algorithm> class WorkerThread { public: void operator()() { std::cout<<"Worker Thread "<<std::endl; } }; int main() { std::thread threadObj( (WorkerThread()) ); // Program will terminate as we have't called either join or detach with the std::thread object. // Hence std::thread's object destructor will terminate the program return 0; } |
Similarly we should not forget call either join() or detach() in case of exceptions. To prevents with we should use RESOURCE ACQUISITION IS INITIALIZATION (RAII) i.e.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <iostream> #include <thread> class ThreadRAII { std::thread & m_thread; public: ThreadRAII(std::thread & threadObj) : m_thread(threadObj) {
} ~ThreadRAII() { // Check if thread is joinable then detach the thread if(m_thread.joinable()) { m_thread.detach(); } } }; void thread_function() { for(int i = 0; i < 10000; i++); std::cout<<"thread_function Executing"<<std::endl; }
int main() { std::thread threadObj(thread_function);
// If we comment this Line, then program will crash ThreadRAII wrapperObj(threadObj); return 0; } |
ps:
這裡說下以前遇到的坑:
建立執行緒後, 記得一定要呼叫join或detach之一, 原來就是忘記呼叫了, 導致莫名其妙的crash. 如果你不知道這個規則, 查這個bug會很麻煩, 因為你不知道為什麼會crash.