简体   繁体   中英

std::thread thread spun off in object, when does it terminate?

If I spin off an std::thread in the constructor of Bar when does it stop running? Is it guaranteed to stop when the Bar instance gets destructed?

class Bar {

public:

Bar() : thread(&Bar:foo, this) {
}

...

void foo() {
  while (true) {//do stuff//}

}

private:
  std::thread thread;

};

EDIT: How do I correctly terminate the std::thread in the destructor?

If I spin off an std::thread in the constructor of Bar when does it stop running?

the thread will run as long as it executing the callable you provided it, or the program terminates.

Is it guaranteed to stop when the Bar instance gets destructed?

No. In order to guarantee that, call std::thread::join in Bar destructor.

Actually, if you hadn't call thread::join or thread::detach prior to Bar::~Bar , than your application will be terminated by calling automatically to std::terminate . so you must call either join (preferable) or detach (less recommended).

you also want to call therad::join on the object destructor because the spawned thread relies on the object to be alive , if the object is destructed while your thread is working on that object - you are using destructed object and you will have undefined behavior in your code.

Short answer: Yes and no. Yes, the thread ends, but not by the usual way (killing the thread), but by the main thread exiting due to a std::terminate call.

Long answer: The thread can only be safely destructed when the underlying function ( thread ) has finished executing. This can be done in 2 ways

  • calling join() , which waits for the thread to finish (in your case, never)
  • calling detach() , which detaches the thread from the main thread (in this case, the thread will end when the main thread closes - when the program terminates).

If the destructor is called if all of those conditions don't apply, then std::terminate is called:

  • it was default-constructed

  • it was moved from

  • join() has been called

  • detach() has been called

The C++ threading facilities do not include a built-in mechanism for terminating a thread. Instead, you must decide for yourself: a) a mechanism to signal the thread that it should terminate, b) that you do not care about the thread being aborted mid-operation when the process terminates and the OS simply ceases to run it's threads any more.

The std::thread object is not the thread itself but an opaque object containing a descriptor/handle for the thread, so in theory it could be destroyed without affecting the thread, and there were arguments for and against automatic termination of the thread itself. Instead, as a compromise, it was made so that destroying a std::thread object while the thread remained running and attached would cause the application to terminate.

As a result, In it's destructor there is some code like this:

~thread() {
    if (this->joinable())
        std::terminate(...);
}

Here's an example of using a simple atomic variable and checking for it in the thread. For more complex cases you may need to consider a condition_variable or other more sophisticated signaling mechanism.

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

class S {
    std::atomic<bool> running_;
    std::thread thread_;
public:
    S() : running_(true), thread_([this] () { work(); }) {}
    void cancel() { running_ = false; }
    ~S() {
        if ( running_ )
            cancel();
        if ( thread_.joinable() )
            thread_.join();
    }
private:
    void work() {
        while ( running_ ) {
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            std::cout << "tick ...\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            std::cout << "... tock\n";
        }
        std::cout << "!running\n";
    }
};

int main()
{
    std::cout << "main()\n";
    {
        S s;
        std::this_thread::sleep_for(std::chrono::milliseconds(2750));
        std::cout << "end of main, should see a tock and then end\n";
    }
    std::cout << "finished\n";
}

Live demo: http://coliru.stacked-crooked.com/a/3b179f0f9f8bc2e1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM