正在泄漏std::thread未定义行为

Is leaking std::thread undefined behaviour?

本文关键字:未定义 thread 泄漏 std      更新时间:2023-10-16

为什么有人会对

感兴趣
  //...
 new std::thread (func,arg1,arg2);
}

std::thread析构函数(不像boost::thread)杀死线程。Func结束是一段时间。我的问题是这是安全的情况:

情况1:假设函数取arg1, arg2的值
情况2:假设函数通过引用获取arg1, arg2——如果你问我,这听起来很糟糕,因为我假设在创建线程的作用域结束时,arg1和arg2将被它们的析构函数清除。

BTW是std::线程析构函数(即AFAIK调用时函数完成)足够聪明,以清除线程使用的所有资源?我的意思是,如果我创建了1M个线程(不是同时),并且所有线程都完成了,我是否泄露了任何永久的东西?

std::thread对象代表一个线程,它不是一个"真正的"线程,这是一个由操作系统管理的概念。

因此,这里你泄漏了一个std::thread对象,因为你没有删除它。永远不调用析构函数但是它所代表的线程会在它的指令结束时结束,就像任何线程一样。

如果析构函数在指令结束之前被调用,例如,如果您将在堆栈上创建该对象,并且在这个新线程中有很多事情要做,则析构函数调用将触发std::terminate()。你需要调用detach()来允许线程在std::thread实例被销毁后继续运行。

这样,当std::thread实例被销毁时,你必须显式地声明是否希望这个线程结束:如果你希望它继续,调用detach();如果您想等待它结束,请调用join()。

所以在你的情况下,你泄漏了内存,但线程应该继续,因为std::thread对象"永远"存在,因为你失去了控制它的任何方法

BTW是std::线程析构函数(即AFAIK调用时函数完成)足够聪明,以清除线程使用的所有资源?我的意思是,如果我创建了1M个线程(不是同时),并且所有线程都完成了,我是否泄露了任何永久的东西?

通常,当堆栈上的对象超出作用域时(或在捕获异常的堆栈展开期间),自动调用析构函数。由于线程对象是使用new在堆上分配的,因此不会自动调用析构函数,因此一些代码需要对该对象进行delete以调用其析构函数。换句话说,当func()结束时,thread的析构函数不会被调用。

这是不是 OK根据最终文本。具体来说,既不是join ed也不是detach ed的线程的析构函数将调用std::terminate

std::thread析构函数不是在回调返回时调用,而是在thread对象超出作用域时调用,就像任何其他对象一样。因此,一个从来没有delete 'd的new 'd线程将永远不会被销毁,泄露任何相关的状态(如果/当程序终止时任何额外的线程仍在运行时,事情可能会发生可怕的错误…)

为了回答你关于生命周期的问题,std::thread就像std::bind一样:它存储参数的副本并将这些副本传递给回调,而不管回调是通过值还是通过引用获取其参数。必须显式地用std::ref包装参数以获得引用语义。在这种情况下,像往常一样,由您来确保没有悬空引用发生(例如,在任何引用的变量超出作用域之前调用thread::join())