繁体   English   中英

std :: thread thread在对象中分离出来,什么时候终止?

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

如果我在Bar的构造函数中关闭std::thread ,它什么时候停止运行? Bar实例被破坏时,它是否可以保证停止?

class Bar {

public:

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

...

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

}

private:
  std::thread thread;

};

编辑:如何正确终止析构函数中的std::thread

如果我在Bar的构造函数中关闭std :: thread,它什么时候停止运行?

只要它执行你提供的调用,或者程序终止,线程就会运行。

当Bar实例被破坏时,它是否可以保证停止?

不。为了保证这一点,在Bar析构函数中调用std::thread::join

实际上,如果你没有在Bar::~Bar之前调用thread::jointhread::detach ,那么你的应用程序将通过自动调用std::terminatestd::terminate 所以你必须要么join (优先)或detach (少推荐)。

你还想在对象析构函数上调用therad::join ,因为生成的线程依赖于对象是活的 ,如果在你的线程处理该对象时对象被破坏 - 你正在使用被破坏的对象而你将有未定义的行为在你的代码中。

简短的回答:是的,不是。 是的,线程结束,但不是通常的方式(杀死线程),而是由于std::terminate调用退出的主线程。

答案很长:只有在底层函数( 线程 )执行完毕后才能安全地破坏线程 这可以通过两种方式完成

  • 调用join() ,等待线程完成(在你的情况下,永远不会)
  • 调用detach() ,它将线程与主线程分离(在这种情况下,线程将在主线程关闭时结束 - 当程序终止时)。

如果在所有这些条件都不适用的情况下调用析构函数,则调用std::terminate

  • 它是默认构造的

  • 它被移走了

  • 已调用join()

  • 已经调用了detach()

C ++线程工具包含用于终止线程的内置机制。 相反,你必须自己决定:a)一个机制来通知线程它应该终止,b)你不关心线程在进程终止时在操作中被中止并且操作系统只是停止运行它的线程任何更多。

std::thread对象不是线程本身,而是包含线程的描述符/句柄的不透明对象,因此理论上它可以在不影响线程的情况下被销毁,并且存在支持和反对线程自动终止的参数。 相反,作为妥协,它是这样做的,以便在线程保持运行和附加时销毁std::thread对象将导致应用程序终止。

结果,在它的析构函数中有一些代码如下:

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

这是一个使用简单原子变量并在线程中检查它的示例。 对于更复杂的情况,您可能需要考虑condition_variable或其他更复杂的信令机制。

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

现场演示: http//coliru.stacked-crooked.com/a/3b179f0f9f8bc2e1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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