简体   繁体   English

为什么`std :: exit`不能按预期触发析构函数?

[英]Why does `std::exit` not trigger destructors as expected?

#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);
}

My compiler is clang 5.0 with -std=c++1z . 我的编译器是带有-std=c++1z clang 5.0

The output is as follows: 输出如下:

 A:1 A:2 A:4 A:5 A:3 ~A:5 ~A:2 ~A:4 ~A:1 

Note that there is no ~A:3 , which means the object A a3 was not destructed. 注意,没有~A:3 ,这意味着对象A a3没有被破坏。

However, according to cppref : 但是,根据cppref

std::exit causes normal program termination to occur. std::exit导致正常程序终止。 Several cleanup steps are performed: 执行几个清理步骤:

The destructors of objects with thread local storage duration ... are guaranteed to be called. 保证具有线程本地存储持续时间的对象的析构函数被调用。

Objects with thread storage duration are guaranteed to be destroyed only for the thread which calls exit . 确保具有线程存储持续时间的对象仅针对调用exit的线程才被销毁。 Quoting C++14 (N4140), [support.start.term] 18.5/8 (emphasis mine): 引用C ++ 14(N4140),[support.start.term] 18.5 / 8(强调我的意思):

 [[noreturn]] void exit(int status) 

The function exit() has additional behavior in this International Standard: 函数exit()在此国际标准中具有其他行为:

  • First, objects with thread storage duration and associated with the current thread are destroyed. 首先,具有线程存储持续时间并与当前线程关联的对象被销毁。 Next, objects with static storage duration are destroyed and functions registered by calling atexit are called. 接下来,销毁具有静态存储持续时间的对象,并调用通过调用atexit注册的函数。 See 3.6.3 for the order of destructions and calls. 有关销毁和调用的顺序,请参见3.6.3。 (Automatic objects are not destroyed as a result of calling exit() .) If control leaves a registered function called by exit because the function does not provide a handler for a thrown exception, std::terminate() shall be called (15.5.1). (通过调用exit()不会破坏自动对象。)如果控件留下了由exit调用的注册函数,因为该函数未提供引发异常的处理程序,则应调用std::terminate() (15.5。 1)。
  • Next, all open C streams (as mediated by the function signatures declared in <cstdio> ) with unwritten buffered data are flushed, all open C streams are closed, and all files created by calling tmpfile() are removed. 接下来,清除所有具有未写入的缓冲数据的打开的C流(由<cstdio>声明的函数签名介导),关闭所有打开的C流,并删除通过调用tmpfile()创建的所有文件。
  • Finally, control is returned to the host environment. 最后,控制权返回到主机环境。 If status is zero or EXIT_SUCCESS , an implementation-defined form of the status successful termination is returned. 如果status为零或EXIT_SUCCESS ,则返回状态成功终止的实现定义形式。 If status is EXIT_FAILURE , an implementation-defined form of the status unsuccessful termination is returned. 如果status为EXIT_FAILURE ,则返回实现定义的状态,表示状态失败终止。 Otherwise the status returned is implementation-defined. 否则,返回的状态是实现定义的。

The standard therefore does not guarantee destruction of objects with thread storage duration associated with other threads than the one calling exit . 因此,该标准不能保证销毁具有与一个调用exit以外的其他线程关联的线程存储持续时间的对象。

The problem here is that when you exit the process, the thread will be (on most modern multi-tasking operating systems) forcibly killed. 这里的问题是,当您退出该进程时,线程(在大多数现代多任务操作系统上)将被强制杀死。 This killing of the thread happens at the OS level, and the OS doesn't know anything about objects or destructors. 杀死线程发生在操作系统级别,并且操作系统对对象或析构函数一无所知。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM