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.
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 #include #include class WorkerThread { public: void operator()() { std::cout<<"Worker Thread "< } }; int main() { std::vector 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::for_each(threadList.begin(),threadList.end(), std::mem_fn(&std::thread::join)); std::cout<<"Exiting from Main Thread"< return 0; } |
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 "< threadObj.detach(); } if(threadObj.joinable()) { std::cout<<"Detaching Thread "< threadObj.detach(); } std::thread threadObj2( (WorkerThread()) ); if(threadObj2.joinable()) { std::cout<<"Joining Thread "< threadObj2.join(); } if(threadObj2.joinable()) { std::cout<<"Joining Thread "< 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 #include #include class WorkerThread { public: void operator()() { std::cout<<"Worker Thread "< } }; 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 #include 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"< } 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.