假设我开始一个std::thread
,然后detach()
所以线程继续执行即使std::thread
,一旦代表它,超出范围。
进一步假设该程序不具有用于接合分离的线程1的可靠协议,所以分离线程仍然运行时main()
退出。
我找不到在什么标准(更准确地说,在N3797 C ++中14征求意见稿),它描述了应该发生什么,无论是1.10也不30.3包含相关措辞。
1另一个,大概相当于,问题是:“可以分离线程都无法再次加入”,因为任何协议你发明了加盟,信令部分将不得不在线程仍在运行工作要做,而OS调度程序可能决定把线程睡眠一小时只是信令与没有办法接收端可靠地检测线程实际完成执行后。
如果运行的main()
已分离线程运行是不确定的行为,那么任何使用std::thread::detach()
是未定义的行为,除非主线程永远不会退出2。
因此,耗尽的main()
与分离的线程中运行必须定义的效果。 问题是: 其中 (在C ++标准 ,不POSIX,不OS文档,......)都处于所定义的那些的效果。
2所述的分离的线程不能加入(在感std::thread::join()
您可以等待来自分离线程的结果(例如,通过从未来std::packaged_task
,或通过一个计数信号或标志和条件变量),但并不保证线程执行结束 。 事实上,除非你把信令部分进入线程的第一个自动对象的析构函数, 就会有,一般是信令代码后运行的代码(析构函数)。 如果操作系统调度主线程消耗分离线程之前的结果并退出运行完后说析构函数,什么都会^威斯康星州规定的情况发生?
答案原来的问题“发生了什么分离线程,当main()
退出”是:
它继续运行(因为标准不说,它已停止),这是明确的,只要倒是没有(自动| thread_local)其他线程或静态对象的变量。
这似乎被允许允许线程管理作为静态对象(在[basic.start.term / 4注云之多,得益于@dyp的指针)。
当静态对象的破坏已完成时会出现问题,因为那时执行进入其中允许在信号处理程序代码只可以执行制度([basic.start.term] / 1,第一句子 )。 C ++标准库的,也就是只有<atomic>
库([support.runtime] / 9,第二个句子 )。 特别是,式中普通排除 condition_variable
(它的实现所定义的是否是保存在一个信号处理程序来使用,因为它不是的一部分<atomic>
)。
除非你在这一点上展开的筹码,很难看到如何避免不确定的行为。
回答第二个问题“可以分离线程都无法再次加盟”是:
是的,与*_at_thread_exit
系列函数( notify_all_at_thread_exit()
std::promise::set_value_at_thread_exit()
,...)。
如脚注指出[2]的问题的,信令条件变量或信号量或原子计数器不足以加入分离的线程(在确保其执行的结束,之前发生的接收感所述由等待线程信令),因为,在一般情况下,会出现例如后执行更多的代码notify_all()
条件变量的,特别是自动和线程局部对象的析构函数。
运行(自动和线程本地对象的析构函数已经-发生 后 )作为线程做的最后一件事信令是什么_at_thread_exit
的功能系列是专为。
因此,为了避免在没有任何实现的保证上面什么标准要求的未定义行为,你需要(手动)加入与分离线程_at_thread_exit
功能做信令或使分离线程只执行这将是安全的代码用于信号处理程序,太。
拆卸螺纹
据std::thread::detach
:
分离线程对象的执行线程,允许执行独立继续。 任何分配的资源将再次线程退出被释放。
从pthread_detach
:
该pthread_detach()函数应当向执行指示该线程存储可以当线程终止时进行回收。 如果线程尚未终止,pthread_detach()不得导致其终止。 多pthread_detach()的效果将调用同一目标线程是不确定的。
拆卸螺纹主要是为了节省资源,如果应用程序并不需要等待一个线程完成(如守护进程,它必须运行,直到进程终止):
- 要释放应用端处理:一个可以让一个
std::thread
对象走出去的范围不加入,通常是什么导致了一个调用std::terminate()
销毁。 - 为了让OS清理线程特定资源( TCB )立即自动线程退出,因为我们明确规定,我们不感兴趣的后来加入的线程,因此,人们不能加入已经分离线程。
杀线程
在进程终止的行为是一样的一个主线程,它至少可以捕捉一些信号。 无论其他线程可以处理的信号并不重要,因为人们可以加入或主线程的信号处理函数调用中终止其他线程。 (相关问题 )
如前所述, 任何线程,无论分离与否,将与其在大多数操作系统过程中死亡 。 这个过程本身可以通过提高的信号,通过调用终止exit()
或通过从主函数返回。 然而,C ++ 11不能并且不尝试定义底层操作系统的确切行为,而一个Java虚拟机的开发者可以可靠地抽象这种差异在一定程度上。 据我所知,充满异国情调的过程和线程模型古平台(到C ++ 11可能不会被移植)和各种嵌入式系统中,这可能有一个特殊的和/或有限的语言库实现,也有限的语言支持,通常发现。
线程支持
如果线程不被支持std::thread::get_id()
应返回无效ID(默认构造std::thread::id
),因为是一个简单的过程,它并不需要一个线程对象和运行的构造一个std::thread
应该抛出std::system_error
。 这就是我所理解的C ++ 11与今天的操作系统一起使用。 如果有一个与线程支持,这并不在它的进程都会产生一个主线程的操作系统,让我知道。
控制线程
如果一个人需要保持在正常关机线程控制,可以做到这一点通过使用同步原语和/或某种标志。 然而,在这种情况下,设定关机标志后跟一个连接是我喜欢的方式,因为有在通过分离线程日益复杂是没有意义的,因为资源将在同一时间反正被释放,其中的几个字节std::thread
对象与更高的复杂性和可能的多个同步原语应是可接受的。
程序退出后,线程的命运是不确定的行为。 但现代操作系统将清理该进程所创建的所有线程上关闭它。
当卸下一个std::thread
,这三个条件将继续持有
-
*this
不再拥有任何线程 - 可连接()总是等于假
- get_id()将等于的std ::螺纹:: 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消息。 操作系统确实清理thread_fn()
只要main()
退出。 更换t1.detach()
与t1.join()
始终打印按预期的消息。
当主线程(也就是运行main()函数的线程)终止,则过程终止,所有其他线程停止。
参考: https://stackoverflow.com/a/4667273/2194843