我什么时候应该使用std :: thread :: detach?

Jin*_*Heo 124 c++ c++11 stdthread

有时我必须使用它std::thread来加速我的应用程序.我也知道join()等待线程完成.这很容易理解,但是呼叫detach()和不呼叫之间的区别是什么?

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

不分离:

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

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

    //some code here
}
Run Code Online (Sandbox Code Playgroud)

呼叫分离:

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

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

    t.detach();

    //some code here
}
Run Code Online (Sandbox Code Playgroud)

Mat*_* M. 127

在析构函数中std::thread,std::terminate如果:

  • 线程未加入(带t.join())
  • 并没有分离(与t.detach())

因此,你应该总是要么joindetach执行的流程之前线程到达析构函数.


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

至关重要的是,这意味着这些线程的堆栈没有被解开,因此一些析构函数不会被执行.根据这些破坏者应该采取的行动,这可能就像程序崩溃或被杀死一样糟糕.希望操作系统将释放文件锁等...但你可能已经损坏共享内存,半写文件等.


那么,你应该使用joindetach

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

  • @JoseQuinteiro:实际上,与其他资源不同,建议*不要*从析构函数加入.问题是加入不会结束*一个线程,它只是等待*结束它,而不像你有一个信号到位导致线程终止你可能会等待很长时间......*阻塞*当前线程的堆栈被解除并阻止*此当前线程*永远终止,从而阻止等待它的线程等等...所以,除非你确定*你可以以合理的数量停止给定的线程时间,最好不要在析构函数中等待它. (4认同)
  • @Matthieu,为什么我们不能加入 std::thread 的析构函数? (2认同)
  • @johnsmith:一个很好的问题!你加入会发生什么?你等到线程完成.如果抛出异常,则执行析构函数......突然,异常的传播将暂停,直到线程终止.它有很多原因,特别是如果它正在等待当前挂起的线程的输入!因此,设计师选择将其作为明确的选择,而不是选择有争议的默认选择. (2认同)

650*_*502 23

你应该调用,detach如果你不打算等待线程完成,join但线程将继续运行直到它完成,然后终止而不让主线程专门等待它.

detach基本上会释放能够实现的资源join.

如果一个线程对象结束它的生命并且既join没有detach被调用也是一个致命错误; 在这种情况下terminate被调用.

  • 你应该提一下,如果线程既没有_joined_也没有_detached_,那么在析构函数中调用_terminate_. (9认同)

use*_*670 15

这个答案的目的是在标题答题,而不是解释之间的差异joindetach。所以应该什么时候std::thread::detach什么使用呢?

在正确维护的 C++ 代码中std::thread::detach根本不应该使用。程序员必须确保所有创建的线程优雅地退出,释放所有获取的资源并执行其他必要的清理操作。这意味着通过调用放弃线程的所有权detach不是一种选择,因此join应该在所有场景中使用。

然而,一些应用程序依赖于可能包含无限期阻塞功能的旧的且通常设计和支持不佳的 API。将这些函数的调用移动到专用线程中以避免阻塞其他东西是一种常见的做法。没有办法让这样的线程优雅地退出,所以使用join只会导致主线程阻塞。在这种情况下, usingdetach将是一种不那么邪恶的替代方案,例如,分配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;
}
Run Code Online (Sandbox Code Playgroud)


Gre*_*ape 9

当你分离线程时,它意味着你join()在退出之前没有它main().

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

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

  • 这并不能回答问题。答案基本上是“当你分离时你就分离”。 (2认同)