有人会对
感兴趣的原因 //...
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不同时)并且所有线程完成,我是否永久地泄露了什么?答案 0 :(得分:10)
std :: thread对象代表一个线程,它不是一个“真正的”线程,它是由OS管理的概念。
因此,在这里你泄漏了一个std :: thread对象,因为你没有删除它。 永远不会调用析构函数。 但它所代表的线程将在它的指令结束时结束,就像任何线程一样。
这样,当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()
的析构函数。