假设我有一个小操作,我想在一个单独的线程中执行。我不需要知道它什么时候完成,也不需要等待它的完成,但是我不希望该操作阻塞我的当前线程。当我编写以下代码时,会崩溃:
void myFunction() {
// do other stuff
std::thread([]()
{
// do thread stuff
});
}
此崩溃可以通过将线程分配给变量并将其分离来解决:
void myFunction() {
// do other stuff
std::thread t([]()
{
// do thread stuff
});
t.detach();
}
为什么必须执行此步骤?还是有更好的方法来创建小的一次性线程?
答案 0 :(得分:3)
Because the std::thread::~thread()
specification says so:
之后的线程对象没有关联的线程(并且可以安全地销毁)
- 它是默认构造的
- 它从...移走了
- join()已被调用
- detach()被称为
除非您想将线程对象(通过移动)返回给调用者,否则看来detach()
是其中唯一有意义的一个。
为什么必须执行此步骤?
考虑线程对象代表执行的长期“线程”(轻量级进程或内核可调度实体或类似对象)。
允许您在线程仍在执行时销毁对象,从而使您无法随后加入(并找到该线程的结果)。该 可能是一个逻辑错误,但即使正确退出程序,也可能导致困难。
还是有更好的方法来创建小的一次性线程?
显然,但是使用线程池在后台运行任务通常要好得多,而不是启动和停止大量短时线程。
您也许可以改用std::async()
,但是如果您尝试丢弃future
,则在某些情况下它会在析构函数中返回 may 块。
答案 1 :(得分:0)
请参见the documentation of the destructor of std:thread
:
如果
*this
具有关联的线程(joinable() == true)
,则会调用std::terminate()
。
您应该明确地说,您不在乎线程将要发生什么,并且可以放开对该线程的任何控制。这就是detach
的目的。
通常,这看起来像一个设计问题,因此崩溃很有意义:很难就这种情况下应该发生的事情提出一个通用且毫不奇怪的规则(例如,您的程序通常也可以终止其执行-应该发生的情况)与线程?)。
答案 2 :(得分:0)
考虑一下:线程A创建线程B,线程A离开其执行范围。线程B的句柄将丢失。现在应该怎么办?有几种可能性,最明显的是:
现在您可以争论哪个更好:1或2?我们(编译器)应如何决定哪一种更好?
因此,设计师所做的工作与众不同:崩溃终止代码,以便开发人员明确选择其中一种解决方案。为了避免隐式(也许是不需要的)行为。这是对您的信号:“嘿,现在注意,这段代码很重要,我(编译器)不想为您决定”。
答案 3 :(得分:0)
基本上,您的用例需要调用detach()
,因为您的用例非常奇怪,而不是C ++试图简化的事情。
虽然Java和.Net巧妙地让您抛弃了一个其关联线程仍在运行的Thread
对象,但是在C ++模型中,Thread
更接近于 线程在某种意义上说Thread
对象的存在与其所引用的执行的生存期(或至少是可连接性)一致。请注意,如果不启动Thread
就不可能创建它(除非是默认构造函数,实际上是在移动语义服务中),或者复制它或从线程中创建一个ID。 C ++希望Thread
使线程寿命更长。
保持这种状况有多种好处。操作系统不必自动对线程的控制数据进行最后的清理,因为一旦Thread
消失了,任何人都无法尝试加入它。由于主线程是最后一个退出的线程(除非存在一些移动的恶作剧),因此更容易确保及时删除带有线程存储的变量。缺少的join
(这是极其的常见错误类型)在运行时会被正确标记。
允许一些线程徘徊在远方,这是 ,但这是不寻常的事情。除非它通过同步对象与您的其他线程进行交互,否则无法确保它完成了原本打算做的事情。分离的线程位于reinterpret_cast
级别:您可以告诉编译器您知道它不知道的东西,但这必须是明确的,而不仅仅是您 didn函数的结果't 通话。