Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;11:如果你不';t为std::thread调用join()_C++_Multithreading_C++11_Stdthread - Fatal编程技术网

C++ C++;11:如果你不';t为std::thread调用join()

C++ C++;11:如果你不';t为std::thread调用join(),c++,multithreading,c++11,stdthread,C++,Multithreading,C++11,Stdthread,如下所示: 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会发生什么情

如下所示:

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::thread::~thread()

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

资料来源:

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

但是请注意,在本例中,
boost::thread::~thread()
调用
detach()
。 (正如用户dyp在注释中所述,这种行为在较新的版本中被弃用)


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

如果调用析构函数时未分离或加入线程,它将调用
std::terminate
,我们可以通过转到“我们看到”部分
30.3.1.3
线程析构函数说明:

如果joinable(),则调用std::terminate()。否则,就没有效果。[ 注意:在中隐式分离或连接可接合()线程 它的析构函数可能导致难以调试正确性(例如 仅当 引发异常。因此程序员必须确保 当线程仍然可连接时,析构函数永远不会执行。-结束 注]

关于这种行为的基本原理,我们可以在

为什么可连接线程的析构函数必须调用 终止?毕竟,析构函数可以与子函数连接 线程,或者它可以从子线程分离,或者它可以取消 线。简而言之,您不能像这样加入析构函数 导致意外(代码中未明确指示)程序 冻结以防f2抛出

下面是一个例子,它还说:

您不能分离,因为这可能会导致主线程 保留启动子线程的作用域,以及子线程 线程保持运行并保持对已存在的作用域的引用 走了


这篇文章引用了一个反对先前建议的论点,即如果可连接,则在销毁时分离,并指出两个备选方案之一是连接,这可能会导致死锁。另一个备选方案是我们今天使用的,即
std::terminate
如果可连接,则在销毁时终止。

在C++11中,当新创建的线程超出作用域时(调用我们的it dtor),必须显式指定“发生了什么”。有时,当我们确信主线程正在继续,并且我们的线程充当“管道”时,可以安全地将它们“分离()”;有时,当我们等待工作线程完成其操作时,我们会“join()”它们

如前所述,程序员必须确保当线程仍然可连接时,不会执行析构函数


指定多线程策略。在本例中,调用了
std::terminate()

为什么不试试?@Drop,因为这不是了解担保的可靠方法。@dyp询问Stackoverflow也不是。通过编译和运行这个5行的示例,他至少可以找到一条线索。保证只有一个来源——标准。@Drop“对Stackoverflow的询问都不是”好的,所以在我看来,答案引用了一个可靠的来源(正如您所做的)。然而,即使是标准本身也不是一个完全可靠的来源,因为它包含缺陷。编译器提供程序通常会偏离字面解释,例如合并缺陷报告的建议解决方案。由于存在未定义的行为,我认为通过尝试来了解担保是不好的做法。我认为“你为什么不尝试一下?”是一个非常有效的回答,如果它表明OP在提问之前费心运行一些实验,那么问题就会得到改善。“我试过了,我的程序被终止了,这是意料之中的吗?”这是一个比“如果我这么做会发生什么?”更好的问题。这不像我们谈论的是吃一些野生的未知浆果,C++11编译器是免费的,运行实验很容易,也很有教育意义。boost的这种行为不受欢迎:@dyp Cool!我可以在我的回答中加上吗?;)“或者它可以取消线程…”“取消”std::线程是什么意思?顺便说一句,值得注意的是,C++20添加了jthread,它在销毁时加入。