Waiting for a std::thread to finish

14,536

Solution 1

Ahh, apparently there's a bug in the runtime library. Threads are not ended successfully in destructors of static objects according to this question. My GameLoop is a non-static object contained in a static GameSystem. I'll check whether this is true and update.

Yep, confirmed. Just my luck to hit a bug on first use!

Solution 2

Of course, when you join a thread that doesn't cause the thread to terminate. It simply blocks until that thread dies of natural (or unnatural) causes.

In order to clean up a multithreaded application gracefully, you need to somehow tell the worker thread that it is time to die, and then wait for the death to happen. The "wait for death to happen" part is what join is for.

Share:
14,536
Kristian D'Amato
Author by

Kristian D'Amato

Game & GPU developer, and C++ fanboy.

Updated on June 09, 2022

Comments

  • Kristian D'Amato
    Kristian D'Amato almost 2 years

    I am trying to clean up gracefully on program termination, so I'm calling join() on a std::thread to wait for it to finish. This simply seems to block the main thread forever, but I don't understand why, because the worker thread is an (almost) empty loop like this:

    void GameLoop::Run()
    {
        while (run)
        {
            //  Do stuff... 
        }   
        std::cout << "Ending thread...\n";
    }
    

    I'm setting run to false before joining, of course. Now, I'm suspecting it's got something to do with it being a member function and being called upon object destruction. I'm creating the thread like this: runThread.reset(new thread(&GameLoop::Run, this));, where runThread is unique_ptr<std::thread> and a member of GameLoop. The join() call comes in the destructor of the GameLoop object.

    Maybe the loop thread cannot finish if its object is in the process of being destroyed? According to the debugger the loop thread lingers on in the dark depths of msvcr120d.dll. If so, how would you handle it?

    Beware: new to std::thread here!

    Update: This is my call to join in the destructor:

    run = false;
    if (runThread->joinable())
    {
        runThread->join();
    }
    

    Update 2: If I remove the join() I get an exception raised by ~thread()!

  • Kristian D'Amato
    Kristian D'Amato over 10 years
    I'm setting run to false. Let me update the question.
  • Lightness Races in Orbit
    Lightness Races in Orbit over 10 years
    Well you'll also want to ensure that run functions properly in a multi-threaded environment.
  • Kristian D'Amato
    Kristian D'Amato over 10 years
    Ok, thanks, I've changed it to an atomic<bool>, but I wonder: for such a small variable like a bool, is there a real concern to make it an atomic, if one thread is only writing and another is only reading?
  • JAB
    JAB over 8 years
    @KristianD'Amato No, if you're comfortable trusting the compiler when the behavior of multiple threads accessing a non-atomic variable is explicitly undefined behavior in C++11.