C++ 何时应该使用std::thread::detach?

C++ 何时应该使用std::thread::detach?,c++,c++11,stdthread,C++,C++11,Stdthread,有时我不得不使用std::thread来加速我的应用程序。我还知道join()会等待线程完成。这很容易理解,但是调用detach()和不调用它有什么区别 我认为如果没有detach(),线程的方法将独立使用线程 不分离: void Someclass::Somefunction() { //... std::thread t([ ] { printf("thread called without detach"); }); //some cod

有时我不得不使用
std::thread
来加速我的应用程序。我还知道
join()
会等待线程完成。这很容易理解,但是调用
detach()
和不调用它有什么区别

我认为如果没有
detach()
,线程的方法将独立使用线程

不分离:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called without detach");
    });

    //some code here
}
void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called with detach");
    });

    t.detach();

    //some code here
}
使用分离调用:

void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called without detach");
    });

    //some code here
}
void Someclass::Somefunction() {
    //...

    std::thread t([ ] {
        printf("thread called with detach");
    });

    t.detach();

    //some code here
}

如果您不打算等待线程完成
join
操作,那么您应该调用
detach
,但是线程将继续运行,直到完成,然后在主线程没有特别等待的情况下终止

detach
基本上会释放实现
join
所需的资源


如果线程对象结束其生命周期,并且既没有调用
join
也没有调用
detach
,则这是一个致命错误;在这种情况下,将调用
terminate

当您分离线程时,意味着您不必在退出
main()
之前
join()

线程库实际上会在main下面等待每个这样的线程,但您不应该关心它


detach()
主要用于您必须在后台完成的任务,但不关心其执行情况。这通常是一些图书馆的情况。他们可能会默默地创建一个后台工作线程并将其分离,这样您甚至不会注意到它。

std::thread
的析构函数中,如果出现以下情况,则调用
std::terminate

  • 线程未连接(使用
    t.join()
  • 并且也没有分离(使用
    t.detach()
因此,在执行流到达析构函数之前,您应该始终
join
detach
线程


当程序终止(即,
main
返回)时,在后台执行的剩余分离线程不会被等待;相反,它们的执行被挂起,线程本地对象被破坏

关键的是,这意味着这些线程的堆栈没有展开,因此一些析构函数没有执行。根据那些析构函数应该采取的行动,这种情况可能和程序崩溃或被杀死一样糟糕。希望操作系统能释放文件上的锁,等等。。。但是您可能损坏了共享内存、半写文件等


那么,您应该使用
join
还是
detach

  • 使用
    join
  • 除非您需要更大的灵活性,并且愿意提供一种同步机制,以便自己等待线程完成,在这种情况下,您可以使用
    detach
根据:

将执行线程与线程对象分离,允许 独立执行。任何分配的资源都将被删除 线程退出后释放

调用detach
*后,此
不再拥有任何线程

例如:

  std::thread my_thread([&](){XXXX});
  my_thread.detach();
注意局部变量:
myu-thread
,当
myu-thread
的生存期结束时,将调用
std::thread
的析构函数,并在析构函数中调用
std::terminate()


但是如果你使用
detach()
,你就不应该再使用
my_线程了,即使
my_线程的生命周期结束了,新线程也不会发生任何事情。

这个答案的目的是回答标题中的问题,而不是解释
join
detach
之间的区别。那么什么时候应该使用
std::thread::detach

在正确维护的C++代码<代码>:::::ToeXCUT/<代码>根本不应该使用。程序员必须确保所有创建的线程正常退出,释放所有获取的资源并执行其他必要的清理操作。这意味着通过调用

detach
放弃线程的所有权不是一个选项,因此
join
应该在所有场景中使用

然而,一些应用程序依赖于旧的、通常设计和支持不好的API,这些API可能包含无限期阻塞函数。将这些函数的调用转移到专用线程中以避免阻塞其他内容是一种常见做法。无法使这样的线程正常退出,因此使用
join
只会导致主线程阻塞。这种情况下,使用
detach
会比分配
thread
对象具有动态存储持续时间,然后故意泄漏它更安全

#include <LegacyApi.hpp>
#include <thread>

auto LegacyApiThreadEntry(void)
{
    auto result{NastyBlockingFunction()};
    // do something...
}

int main()
{
    ::std::thread legacy_api_thread{&LegacyApiThreadEntry};
    // do something...
    legacy_api_thread.detach();
    return 0;
}
#包括
#包括
自动LegacyApiThreadEntry(无效)
{
自动结果{NastyBlockingFunction()};
//做点什么。。。
}
int main()
{
::std::threadlegacy_api_thread{&LegacyApiThreadEntry};
//做点什么。。。
旧版_api_thread.detach();
返回0;
}

std
boost
线程可能重复的
detach
join
都是紧跟POSIX线程建模的;在main()中,则不会从main()调用exit(),因此程序将继续执行,直到所有分离的线程完成为止。然后会调用exit()。@Matthieu,为什么我们不能加入std::thread的析构函数?@johnsmith:一个很好的问题!当你加入时会发生什么?等待线程完成。如果抛出异常,将执行析构函数。。。突然,异常的传播被挂起,直到线程终止。有很多理由不这样做,特别是当它正在等待来自当前挂起线程的输入时!所以设计师们选择了一个明确的选择,而不是选择一个有争议的默认值。@Matthieu我想你的意思是调用join