thread_local变量为何在线程返回时未销毁?是否符合C++标准?
测试代码
// code 1 #include <iostream> #include <thread> struct tls_test { tls_test() { std::cout << "tls_test ctor\n"; } ~tls_test() { std::cout << "tls_test dtor\n"; } void print() const { std::cout << "tls_test print\n"; } }; thread_local tls_test t; void thread_1() { std::cout << "thread_1 started\n"; t.print(); std::cout << "thread_1 return\n"; } int main() { std::thread trd{ thread_1 }; trd.join(); std::cout << "main return\n"; }
测试环境与输出
使用TDM-GCC + Windows 10测试,程序输出如下:
thread_1 started tls_test ctor tls_test print thread_1 return main return
疑问
根据C++标准中basic.stc.thread的规定,thread_local变量构造后应在线程退出时销毁,但从输出看,线程函数thread_1返回后,变量t的析构函数并未执行,直到main返回都没输出析构信息。这种行为是否符合标准?若符合,原因是什么?线程何时才会退出?
解答
这种行为符合C++标准,核心原因和Windows平台的线程实现、TDM-GCC的运行时机制有关:
标准对线程退出的定义
C++标准仅规定thread_local变量的生命周期与线程绑定:首次访问时构造,线程退出时销毁,但并未强制要求析构动作必须在线程函数返回后立即执行,只要最终在线程完全终止前完成即可。这里的“线程退出”是逻辑上的线程执行终止,具体的资源清理时机允许平台根据自身实现策略调整。Windows平台的TLS特性
Windows系统的线程本地存储(TLS)资源,默认是在进程退出时统一回收,而非线程退出时即时清理。TDM-GCC基于MinGW运行时库,依赖Windows原生TLS机制实现thread_local变量,因此会继承这一特性:当thread_1返回、join完成后,线程的TLS槽并未被系统立即释放,变量t的析构函数也就不会触发,直到整个进程(main函数返回后)退出,系统才会清理所有剩余的TLS资源,执行析构。跨平台差异验证
如果在Linux等其他平台测试同一段代码,会看到thread_1返回后立即输出t的析构信息——这是因为Linux的线程TLS实现策略是在线程退出时即时清理资源,但两种行为都符合C++标准的要求,只是平台实现细节不同。
内容的提问来源于stack exchange,提问作者iTruth

