#include <cstdlib>
#include <thread>
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::literals;
struct A
{
int n_ = 0;
A(int n) : n_(n) { cout << "A:" << n_ << endl; }
~A() { cout << "~A:" << n_ << endl; }
};
A a1(1);
int main()
{
std::thread([]()
{
static A a2(2);
thread_local A a3(3);
std::this_thread::sleep_for(24h);
}).detach();
static A a4(4);
thread_local A a5(5);
std::this_thread::sleep_for(1s);
std::exit(0);
}
我的编译器为clang 5.0
-std=c++1z
。
输出如下:
A:1 A:2 A:4 A:5 A:3 ~A:5 ~A:2 ~A:4 ~A:1
请注意,没有~A:3
,这意味着对象A a3
未被破坏。
然而,根据cppref:
std::exit
会导致正常的程序终止。几个清理步骤是 进行:具有线程本地存储持续时间的对象的析构函数... 保证被叫。
答案 0 :(得分:37)
保证仅为调用exit
的线程销毁具有线程存储持续时间的对象。引用C ++ 14(N4140),[support.start.term] 18.5 / 8(强调我的):
[[noreturn]] void exit(int status)
函数
exit()
在本国际标准中有其他行为:
- 首先,销毁线程存储持续时间且与当前线程关联的对象。 接下来,通过调用atexit来销毁具有静态存储持续时间的对象并注册函数 叫做。有关破坏和调用的顺序,请参见3.6.3。 (自动对象不是 因调用
exit()
而被销毁。) 如果控制离开由exit
调用的注册函数,因为该函数不提供 抛出异常的处理程序,std::terminate()
将被调用(15.5.1)。- 接下来,所有打开的C流(由
<cstdio>
中声明的函数签名调解) 刷新未写入的缓冲数据,关闭所有打开的C流,并通过调用创建所有文件tmpfile()
已被移除。- 最后,控制权返回给主机环境。如果状态为零或
EXIT_SUCCESS
,则为 返回状态成功终止的实现定义形式。如果状态为EXIT_FAILURE
,则返回状态为不成功终止的实现定义形式。 否则返回的状态是实现定义的。
因此,该标准不保证销毁与调用exit
的线程之外的其他线程相关联的线程存储持续时间的对象。
答案 1 :(得分:14)
这里的问题是当你退出进程时,线程将(在大多数现代多任务操作系统上)被强行杀死。这种线程的杀死发生在操作系统级别,操作系统对对象或析构函数一无所知。