繁体   English   中英

C++11:如果不为 std::thread 调用 join() 会发生什么

[英]C++11: What happens if you don't call join() for std::thread

下面给出:

void test() 
{
  std::chrono::seconds dura( 20 );
  std::this_thread::sleep_for( dura );
}

int main()
{
  std::thread th1(test);
  std::chrono::seconds dura( 5 );
  std::this_thread::sleep_for( dura );
  return 0;
}

main将在 5 秒后退出,仍在执行的th1会发生什么?

即使您在main定义的th1线程对象超出范围并被销毁,它是否会继续执行直到完成?

th1是否只是在它完成执行后就坐在那里,或者在程序终止时以某种方式被清除?

如果线程是在函数中创建的,而不是在main创建的 - 线程是否会一直存在直到程序终止或函数超出范围?

如果您想要线程上的某种类型的超时行为,那么简单地不为线程调用join是否安全?

如果在调用析构函数时您没有分离或加入线程,它将调用std::terminate ,我们可以通过转到C++11 标准草案来看到这一点,我们看到第30.3.1.3线程析构函数说:

如果 joinable(),则调用 std::terminate()。 否则,没有任何影响。 [ 注意:在其析构函数中隐式分离或加入 joinable() 线程可能会导致难以调试正确性(对于分离)或性能(对于连接)错误,只有在引发异常时才会遇到。 因此,程序员必须确保在线程仍可连接时永远不会执行析构函数。 ——尾注]

至于这种行为的基本原理,我们可以 使用 std::thread(Not) 中找到一个很好的总结

为什么可连接线程的析构函数必须调用 std::terminate? 毕竟,析构函数可以加入子线程,也可以与子线程分离,或者取消线程。 简而言之,您不能加入析构函数,因为如果 f2 抛出,这将导致意外(未在代码中明确指出)程序冻结。

一个例子如下,还说:

您不能分离,因为这会导致主线程离开启动子线程的作用域,而子线程继续运行并保留对已经消失的作用域的引用的情况。

该文章引用了N2802:请求重新考虑线程对象的 detach-on-destruction,这是反对先前提议的论点,如果可连接,则在破坏时分离,并指出两种选择之一是 join,这可能导致死锁另一种选择是我们今天所拥有的,如果可连接,则std::terminate销毁。

std::thread::~thread()

如果 *this 有关联线程( joinable() == true ),则调用std::terminate()

来源: http : //en.cppreference.com/w/cpp/thread/thread/~thread

这意味着像这样的程序根本不是格式良好或安全的。

但是请注意,在这种情况下, boost::thread::~thread()调用detach() (正如用户dyp在评论中所述,此行为在最近的版本中已被弃用)

您始终可以使用 RAII 解决此问题。 只需将您的线程包装在另一个类中,这将具有所需的销毁行为。

在 C++11 中,当新创建的线程超出范围(我们的 dtor 被调用)时,您必须明确指定“会发生什么”。 有时,当我们确定主线程正在继续并且我们的线程充当“管道”时,“分离()”它们是安全的; 有时当我们等待我们的 WORKER 线程完成它们的操作时,我们“加入()”它们。

正如所说,程序员必须确保在线程仍可连接时永远不会执行析构函数。

指定您的多线程策略。 在这个例子中, std::terminate()被调用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM