Search code examples
c++multithreadingjoindetach

Self terminating thread. Use join or detach


I have a state machine being processed within a std::thread. This state machine initializes a network connection, processes data, and upon the receipt of a certain message, needs to shut itself down. Using join in this fashion triggers the 'abort() has been called' exception. Is this one of the cases where a detached thread is appropriate.

#include <iostream>

#include <thread>
#include <atomic>
#include <memory>

class ThreadExample
{
public:
    ThreadExample()
    {
        StartThread();
    }

    void StartThread()
    {
        //start thread;
        run_thread = true;
        the_thread = std::thread(&ThreadExample::ThreadFunction, this);
    }

    void ThreadFunction()
    {
        while (run_thread)
        {
            if (correct_message_found)
                ShutdownThread();
            else
                ProcessMessage();   //example code to imitate network processing

            //arbitrary wait. not relevant to the problem
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }

    //read in by some network connection
    void ProcessMessage(/*some message data*/)
    {
        static int counter = 0;
        if (counter == 3)
        {
            correct_message_found = true;
        }
        else
        {
            std::cout << "Waiting for the right message\n";
            counter++;
        }
    }

    void ShutdownThread()
    {
        run_thread = false;
        if (the_thread.joinable())
            the_thread.join();
    }

private:
    std::thread the_thread;
    std::atomic_bool run_thread;
    bool correct_message_found = false;
};

int main()
{
    auto example = std::make_unique<ThreadExample>();

    int data;
    std::cin >> data;
}

Solution

  • The correct way to terminate a thread from inside itself is to simply return from the function the thread is executing:

    void ThreadFunction()
    {
        while (run_thread)
        {
            if (correct_message_found)
                return;
            else
                ProcessMessage();   //example code to imitate network processing
    
            //arbitrary wait. not relevant to the problem
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    

    Calling join from within the thread that is supposed to be joined is an error, see the first error condition: https://en.cppreference.com/w/cpp/thread/thread/join

    join means "wait for the given thread to finish, then continue on". You are telling a thread to wait until it itself is finished. So it can only end once it has already ended, which is clearly contradictory.

    Where you should call join is in the destructor of ThreadExample. ThreadFunction uses members of ThreadExample, and ThreadExample also owns the std::thread object, so ThreadExample cannot be allowed to die while the thread is still running. In the code you show, you would run into that problem if you input something before the thread is done: ThreadExample is then destroyed, and with it the std::thread object living inside. If a std::thread is destroyed while joinable (i.e. with a non-detached thread still running) then std::terminate is called:
    https://en.cppreference.com/w/cpp/thread/thread/%7Ethread