CPP 11 Multithreading – Part 2: Joining and Detaching Threads | std::thread::join() & std::thread::detach() Methods with Examples

Thread join c++: In the previous article, we have discussed about How to trim strings in C++ using Boost String Algorithm Library. Let us learn how to find Multithreading – Part 2 in C++ Program.

Let’s discover this tutorial for getting more knowledge about C++11 Multithreading Part-2.  Here we are going to learn what is joining and detaching threads of std::thread. Apart from that, you may also see the explanation of std::thread::join() & std::thread::detach() Methods with Examples. So, stay tuned to this tutorial easily via available quick links.

Joining Threads with std::thread::join()

Std thread join: When the first thread is started then the other thread that is going to start yet should wait for the first thread to finish. For this, another we need to call the join() function on the std::thread object.

Syntax:

std::thread th(funcPtr);

// Some Code

th.join();

Suppose Main Thread has to start 10 Worker Threads and after starting all these threads, the main function will wait for them to finish. After joining all the threads the main function will continue.

So, let’s take an example. There is one main thread and some worker threads after joining all the threads the main function will continue. The main function will wait for them to finish.

#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <functional>
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 background threads sometimes also called daemon threads. To detach a thread we need to call std::detach() function on std::thread object. ie.,

std::thread th(funcPtr);
th.detach();

Once you call the detach(), then the std::thread object is no longer connected with the actual thread of execution.

Also Check:

Be cautious with calling detach() and join() on Thread Handles

We have to be careful on calling detach() and join() on thread handles. We are going to discuss some cases below for this:

Case 1: Never call join() or detach() on std::thread object with no associated executing thread

std::thread threadObj( (WorkerThread()) );
   threadObj.join();
   threadObj.join(); // It will cause Program to Terminate

When a join() function called on a thread object, join returns 0 then that ‘td::thread’ object has no associated thread with it. If the join() function again called on such an object then it will cause the program to Terminate. Similarly, detach() function will work.

Syntax:

std::thread threadObj( (WorkerThread()) );
   threadObj.detach();
   threadObj.detach(); // It will cause Program to Terminate

Before calling join() or detach() we should check if the thread is join-able every time or not,

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

In this case, if neither join nor 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.

#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 to call either join() or detach() in case of exceptions.

To prevent this with we should use Resource Acquisition Is Initialization (RAII) which is show below,

#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;
}

Conclusion:

In this article, we have discussed completely regarding C++11 Multithreading joining and detaching threads of std::thread and some risk cases. Thank you!