泄漏std :: thread未定义的行为?

时间:2011-09-13 18:22:56

标签: c++ multithreading c++11

有人会对

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

}

std::thread析构函数(与boost::thread不同)杀死线程。 func完成是一段时间。 我的问题是这种情况下的安全:

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

BTW是std :: thread析构函数(当func完成时调用AFAIK)足够聪明地清除线程使用的所有资源?我的意思是,如果我用新的线程创建1M线程(ofc不同时)并且所有线程完成,我是否永久地泄露了什么?

3 个答案:

答案 0 :(得分:10)

std :: thread对象代表一个线程,它不是一个“真正的”线程,它是由OS管理的概念。

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

If the destructor was called before the end of the instructions, for example if you would have created that object on the stack and there was a lot of things to do in this new thread, then the destructor call would have triggered std::terminate(). You need to call detach() to allow the thread to continue after the std::thread instance is destroyed.

这样,当std :: thread实例被销毁时,你必须明确地说出你是否想要这个线程结束:如果你想让它继续,请调用detach();如果你想等待它结束,请调用join()。

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

答案 1 :(得分:1)

根据最终文本,确定。具体来说,既没有join也没有detach ed的线程的析构函数将调用std::terminate

回调返回时不会调用

std::thread析构函数,但是当thread对象超出范围时,就像任何其他对象一样。因此,一个永远不会new'的delete'线程将永远不会被破坏,泄漏任何相关状态(如果/当程序终止时任何额外的线程仍在运行时,事情可能会出现严重错误。 ..)

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

答案 2 :(得分:1)

  BTW是std :: thread析构函数(当func完成时调用AFAIK)足够聪明地清除线程使用的所有资源?我的意思是如果我用新的线程创建1M线程(并非同时),并且所有线程都完成了,我是否永久地泄露了什么?

通常,当堆栈中的对象超出范围时(或者在捕获异常时堆栈展开期间)会自动调用析构函数。由于线程对象是使用new在堆上分配的,因此不会自动调用析构函数,某些代码需要delete对象来调用其析构函数。换句话说,thread完成时不会调用func()的析构函数。