当main()退出时,分离的线程会发生什么?

假设我开始一个std::thread ,然后detach()它,所以线程继续执行,即使曾经表示它的std::thread超出了范围。

进一步假定程序没有用于join分离线程1的可靠协议,因此当main()退出时分离的线程仍然运行。

我无法find标准中的任何内容(更准确地说,在N3797 C ++ 14草案中),它描述了应该发生的事情,1.10和30.3都没有包含相关的措词。

1另一个可能相同的问题是:“是否可以再次连接一个分离的线程”,因为无论您正在创build哪个协议,都必须在线程仍在运行时完成信号部分,OS调度器可能决定让线程在信号传输完成后立即睡眠一个小时,而接收端无法可靠地检测到线程实际完成。

如果用分离线程运行的main()运行是未定义的行为,那么除非主线程永不退出,否则任何std::thread::detach()都是未定义的行为。

因此,运行分离线程的main()运行必须具有已定义的效果。 问题是: 在哪里 (在C ++标准中 ,不是POSIX,不是OS文档,…)是定义的那些效果。

2分离的线程不能被连接( std::thread::join() )。 您可以等待来自分离线程的结果(例如,通过来自std::packaged_task的未来,或通过计数信号量或标志和条件variables),但是不能保证线程已经完成执行 。 事实上,除非将信令部分放入线程的第一个自动对象的析构函数中,否则通常会在信号代码之后运行代码(析构函数)。 如果操作系统安排主线程使用结果,并在分离的线程结束运行析构函数之前退出,那么^ Wis定义了什么?

分离线程

根据std::thread::detach

将执行线程从线程对象中分离出来,允许独立执行。 一旦线程退出,任何分配的资源都将被释放。

pthread_detach

pthread_detach()函数应该向实现指示线程终止时线程的存储可以被回收。 如果线程还没有终止,pthread_detach()不会导致它终止。 未指定多个pthread_detach()调用对同一目标线程的影响。

分离线程主要用于节省资源,以防应用程序不需要等待线程完成(例如守护程序,它必须运行直到进程终止):

  1. 释放应用程序端句柄:可以让一个std::thread对象超出范围而不join,通常会导致在销毁时调用std::terminate()
  2. 为了允许操作系统在线程退出时自动清理线程特定的资源( TCB ),因为我们明确地指定了,我们以后不想join线程,所以不能join已经分离的线程。

杀死线程

进程终止的行为与主线程相同,至less可以捕获一些信号。 其他线程是否可以处理信号并不重要,因为可以在主线程的信号处理程序调用中join或终止其他线程。 (相关问题 )

如前所述, 任何线程,无论是否分离,都会在大多数操作系统上死亡 。 这个过程本身可以通过调用exit()或者从main函数返回来提高信号来终止。 但是,C ++ 11不能也不会试图定义底层操作系统的确切行为,而Java VM的开发人员肯定会在一定程度上抽象出这些差异。 AFAIK,奇特的进程和线程模型通常在古老的平台上(C ++ 11可能不会移植到这个平台上)以及各种embedded式系统上,这些embedded式系统可能有特殊的和/或有限的语言库实现,也有限的语言支持。

线程支持

如果线程不支持std::thread::get_id()应该返回一个无效的id(默认构造的std::thread::id ),因为有一个普通的进程,它不需要线程对象来运行和一个std::thread应该抛出一个std::system_error 。 这就是我如何理解C ++ 11与今天的操作系统。 如果有一个带有线程支持的操作系统,它不会在其进程中产生一个主线程,请告诉我。

控制线程

如果需要保持对线程的正确closures控制,可以使用同步原语和/或某种标志来实现。 但是,在这种情况下,设置一个closures标志后跟一个连接是我喜欢的方式,因为通过分离线程增加复杂性是没有意义的,因为无论如何资源将被同时释放, std::thread的几个字节std::thread对象与更高的复杂性和可能更多的同步原语应该是可以接受的。

原始问题“ main()退出时分离的线程会发生什么”的答案是:

它继续运行(因为标准没有说它停止了),而且这是很好的定义,只要它既不接触其他线程的variables(自动| thread_local)也不接受静态对象。

这似乎是允许线程pipe理器作为静态对象(注意在[basic.start.term] / 4说,尽可能多,由于@dyp的指针)。

当静态对象的销毁已经完成时会出现问题,因为那么执行进入一个只有信号处理程序允许的代码可以执行的机制( [basic.start.term] / 1,第一句 )。 在C ++标准库中,只有<atomic>库( [support.runtime] / 9,第二句 )。 尤其是,通常condition_variable不包括 condition_variable (它是实现定义的,不pipe是在信号处理程序中保存使用,因为它不是<atomic>一部分)。

除非你已经解开你的堆栈,否则很难看到如何避免未定义的行为。

第二个问题的答案是“可以分离的线程再次被连接”:

是的,使用*_at_thread_exit函数家族( notify_all_at_thread_exit()std::promise::set_value_at_thread_exit() ,…)。

正如问题脚注[2]所指出的那样,指示条件variables或信号量或primefaces计数器不足以join分离的线程(就确保其执行的结束已经发生的意义而言)由等待线程发出信号),因为通常情况下,在例如条件variables的notify_all()之后会执行更多的代码,特别是自动和线程局部对象的析构函数。

运行信号作为线程最后一件事情(自动和线程局部对象的析构函数发生之后 )是_at_thread_exit系列函数的devise目的。

所以,为了避免在没有任何实现保证的情况下的未定义的行为,你需要(手动)用一个_at_thread_exit函数join一个分离的线程来执行信令, 或者让分离的线程执行那些安全的代码对于信号处理程序也是如此。

程序退出后线程的命运是未定义的行为。 但是一个现代化的操作系统会清理进程closures时创build的所有线程。

当分离std::thread ,这三个条件将继续保持

  1. *this不再拥有任何线程
  2. joinable()将始终等于false
  3. get_id()将等于std :: thread :: id()

考虑下面的代码:

 #include <iostream> #include <string> #include <thread> #include <chrono> void thread_fn() { std::this_thread::sleep_for (std::chrono::seconds(1)); std::cout << "Inside thread function\n"; } int main() { std::thread t1(thread_fn); t1.detach(); return 0; } 

在Linux系统上运行,thread_fn的消息永远不会被打印。 一旦main()退出,OS确实清理了thread_fn() 。 用t1.detach()replacet1.join()总是按预期打印消息。

当主线程(即运行main()函数的线程)终止时,进程终止,所有其他线程停止。

参考: https : //stackoverflow.com/a/4667273/2194843