简体   繁体   English

_Exit如何在C ++程序中运行?

[英]How will _Exit behave in a C++ program?

C99 offers the _Exit function, which exits "immediately", although it does may close file descriptors. C99提供了_Exit功能,“立即”退出,虽然 可能会关闭文件描述符。 Unix/POSIX extends this behavior by mandating the closing of all fd's without flushing (and offers the synonym _exit ). Unix / POSIX通过强制关闭所有fd而不刷新来扩展此行为(并提供同义词_exit )。

Will these functions call destructors for static objects when called from a C++ program? 当从C ++程序调用时,这些函数会调用static对象的析构函数吗? Does the C++ standard make any guarantees about _Exit ? C ++标准是否对_Exit做出任何保证?

(Inspired by this question ; I suddenly wondered what happens in the typical fork - exec - _exit idiom in C++.) (受这个问题的启发;我突然想知道在C ++中典型的fork - exec - _exit成语会发生什么。)

First, no form of program exit will automatically call destructors for heap objects (implied in ISO/IEC 14882:1998(E) 12.4.10). 首先,任何形式的程序退出都不会自动调用堆对象的析构函数(隐含在ISO / IEC 14882:1998(E)12.4.10中)。

Calling exit() will not call destructors for objects with automatic duration, as it does not return through their enclosing scopes (3.6.1.4). 调用exit()不会为具有自动持续时间的对象调用析构函数,因为它不会通过其封闭范围返回(3.6.1.4)。 However, destructors for static objects will be called, in reverse order of construction (18.3.8). 但是, 按照构造的相反顺序调用静态对象的析构函数(18.3.8)。

Calling abort() does not call any destructors for any type of object, nor does it call atexit() registered functions (18.3.3). 调用abort()不会为任何类型的对象调用任何析构函数,也不会调用atexit()注册的函数(18.3.3)。 The C++ standard copy I have here is a bit dated and does not mention _exit or _Exit directly, but I'd imagine that, if present, they should behave the same - that is, not calling any destructors. 我在这里的C ++标准副本有点过时,并没有直接提到_exit_Exit ,但我想,如果存在,它们的行为应该相同 - 也就是说,不要调用任何析构函数。 In particular, in the C99 standard, _Exit() skips atexit handlers (it is implementation defined whether stream buffers are flushed, open streams are closed, or temporary files removed). 特别是,在C99标准中, _Exit()跳过atexit处理程序(实现定义是否刷新流缓冲区,关闭打开的流,还是删除临时文件)。

Further note that abort() can be cancelled by trapping signal SIGABRT (ISO/IEC 9899:1999 (E) 7.20.4.1.2 - I only have C99 here but I expect it would be the same in the version referenced by C++). 进一步注意,可以通过捕获信号SIGABRT来取消abort() (ISO / IEC 9899:1999(E)7.20.4.1.2 - 我这里只有C99但我希望它在C ++引用的版本中是相同的)。 _Exit() cannot. _Exit()不能。

On a more practical note, on most unix implementations of abort() and _exit() , abort() raises a SIGABRT while _exit() simply calls an operating system call to terminate the process immediately. 更实际的是,在abort()_exit()大多数unix实现中, abort()引发SIGABRT_exit()只是调用操作系统调用来立即终止进程。 This means that the main differences are: 这意味着主要的区别是:

  • You can specify an exit code for _exit() 您可以为_exit()指定退出代码
  • abort() may be trapped by a signal handler abort()可能被信号处理程序捕获
  • Depending on system configuration, OS, and ulimits, abort() may result in a core dump or similar 根据系统配置,操作系统和ulimits, abort()可能会导致核心转储或类似情况

In a fork()/exec() pattern, _exit() would probably be preferable, to avoid the possibility of core dump. fork()/exec()模式中, _exit()可能更可取,以避免核心转储的可能性。

It simply doesn't exist in standard C++, so there are no guarantees. 它在标准C ++中根本不存在,因此无法保证。

It is planned for inclusion in C++0x. 列入的C ++ 0x。 That specifies (§18.5): 这指定(§18.5):

The function _Exit(int status) has additional behavior in this International Standard: 函数_Exit(int status)在本国际标准中有其他行为:

— The program is terminated without executing destructors for objects of automatic, thread, or static storage duration and without calling functions passed to atexit() (3.6.3). - 程序终止而不执行自动,线程或静态存储持续时间对象的析构函数,并且不调用传递给atexit()的函数(3.6.3)。

Followup: 跟进:

ISO approved C++0x on August 12, 2011. ISO于2011年8月12日批准了C ++ 0x。

Technically, _Exit is not defined by the C++ standard, so you can't even call it from a 100% portable C++ program. 从技术上讲, _Exit不是由C ++标准定义的,因此您甚至无法从100%可移植的C ++程序中调用它。 The C++03 standard incorporates by reference the C89 standard (aka C90 or ANSI C), whereas _Exit is only defined in the newer C99 standard. C ++ 03标准通过引用并入C89标准(又名C90或ANSI C),而_Exit仅在较新的C99标准中定义。 I'm not sure which version of C the upcoming C++0x standard incorporates, but I would guess that it's based on C99. 我不确定即将推出的C ++ 0x标准包含哪个版本的C,但我猜它是基于C99的。

In any case, though, here are the relevant clauses from the relevant language standards: 但无论如何,这里是相关语言标准的相关条款:

_Exit is not guaranteed to close file descriptors. _Exit不保证关闭文件描述符。 From C99 §7.20.4.4/2 (emphasis mine): 从C99§7.20.4.4/ 2(强调我的):

The _Exit function causes normal program termination to occur and control to be returned to the host environment. _Exit函数会导致正常的程序终止,并将控制权返回给主机环境。 No functions registered by the atexit function or signal handlers registered by the signal function are called. 没有通过注册的功能atexit由注册的函数或信号处理signal函数被调用。 The status returned to the host environment is determined in the same way as for the exit function (7.20.4.3). 返回到主机环境的状态的确定方式与exit功能(7.20.4.3)相同。 Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed is implementation-defined. 是否刷新具有未写入缓冲数据的开放流,关闭打开流,或者删除临时文件是实现定义的。

Recall that implementation-defined means that the implementation (that is, the compiler toolchain and runtime environment) can choose to do whatever it wants, but it must document what it does . 回想一下, 实现定义意味着实现(即编译器工具链和运行时环境)可以选择做任何想做的事情,但它必须记录它的作用

From C++03 §3.6.3/1: 来自C ++03§3.6.3/ 1:

Destructors (12.4) for initialized objects of static storage duration (declared at block scope or at namespace scope) are called as a result of returning from main and as a result of calling exit (18.3). 用于静态存储持续时间的初始化对象的析构函数(12.4)(在块作用域或命名空间作用域中声明)作为从main返回并由于调用exit (18.3)的结果而被调用。 These objects are destroyed in the reverse order of the completion of their constructor or of the completion of their dynamic initialization. 这些对象以其构造函数完成或动态初始化完成的相反顺序销毁。 If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized. 如果对象是静态初始化的,则对象的破坏顺序与对象动态初始化的顺序相同。 For an object of array or class type, all subobjects of that object are destroyed before any local object with static storage duration initialized during the construction of the subobjects is destroyed. 对于数组或类类型的对象,在销毁子对象构造期间初始化静态存储持续时间的任何本地对象之前,将销毁该对象的所有子对象。

§3.6.3/4: §3.6.3/ 4:

Calling the function 调用函数

void abort();

declared in <cstdlib> terminates the program without executing destructors for objects of automatic or static storage duration and without calling the functions passed to atexit() . <cstdlib>声明的终止程序,不会为自动或静态存储持续时间的对象执行析构函数,也不会调用传递给atexit()的函数。

Practically, in most implementations, global object destructors are implemented via atexit , so what you will see is that _Exit will not call the destructors for global objects, although this behavior is not guaranteed (since _Exit and C++ are not guaranteed to both exist in the same language). 实际上,在大多数实现中,全局对象析构函数是通过atexit实现的,所以你会看到_Exit不会为全局对象调用析构函数,虽然这种行为不能得到保证(因为_Exit和C ++不能保证都存在于同一种语言)。

Note that while C++ does not specify _Exit and C99 leaves it implementation-defined whether it flushes buffers, POSIX requires that it not flush buffers (since this would break the main usage of _exit / _Exit , ie handling failure of execve after fork ). 请注意,虽然C ++没有指定_Exit而C99让它实现定义是否刷新缓冲区,但POSIX 要求它不刷新缓冲区(因为这会破坏_exit / _Exit的主要用法,即在fork之后处理execve失败)。 As POSIX does not align itself with C++ standards or defer to them on anything, I think it's very unlikely that a future version of the C++ standard would try to change any of this. 由于POSIX没有与C ++标准保持一致或者在任何事情上遵守它们,我认为未来版本的C ++标准不太可能试图改变这一点。 It will probably either leave _Exit unspecified or specify that it's implementation-defined. 它可能要么未指定_Exit要么指定它是实现定义的。

C++0x defines a new function called std::quick_exit that terminates a process without calling any destructors. C ++ 0x定义了一个名为std :: quick_exit的新函数,它终止进程而不调用任何析构函数。 Just checked, g++-4.4.5 already provides it. 刚刚检查过,g ++ - 4.4.5已经提供了它。

There is an interesting analysis here in relation with concurrency and object destruction. 有一个有趣的分析, 在这里与并发性和对象关系的破坏。 As far as I know, destructors will not be called. 据我所知,析构函数不会被调用。 There is nothing about it in the current standard. 目前的标准中没有任何关于它的内容。

Calling of static destructors is defined in terms of atexit. 静态析构函数的调用是根据atexit定义的。 _exit (or _Exit) is defined not to run atexit handlers. _exit(或_Exit)定义为不运行atexit处理程序。 So static destructors should not be called by any implementation. 因此,任何实现都不应调用静态析构函数。

Automatic destructors are not even called when calling exit(). 调用exit()时甚至不调用自动析构函数。

So any sane definition of _Exit semantics for C++ would not run destructors. 因此,C ++的_Exit语义的任何理智定义都不会运行析构函数。

I did a quick test with gcc on Mac OS and my destructors didn't get called. 我在Mac OS上用gcc进行了快速测试,我的析构函数没有被调用。

struct A
{
    ~A()
    {
        puts("A::~A");
    }
};

A globalA;

int main()
{
    A localA;
    _exit(0); // or _Exit(0)
    return 0;
}

exit(0) on the other hand calls globalA 's destructor. 另一方面, exit(0) 调用 globalA的析构函数。

fork() , exec() , and _exit() are all defined by POSIX and they pre-date C99's _Exit() by many years. fork()exec()_exit()都是由POSIX定义的,它们将C99的_Exit()预定多年。 Programs that use fork / exec / _exit are not portable to every system that supports C++. 使用fork / exec / _exit程序不能移植到支持C ++的每个系统。

With regard to _exit() specifically, it is an operating system call that (under POSIX) will close files and terminate the process directly (but not necessarily quickly). 特别是关于_exit() ,它是一个操作系统调用(在POSIX下)将关闭文件并直接终止进程(但不一定很快)。 This would bypass any C++ mechanisms for calling destructors. 这将绕过用于调用析构函数的任何C ++机制。

Even with _Exit() or similar being provided by C++0x, I doubt if there would be much reason to use that in conjunction with fork. 即使C ++ 0x提供了_Exit()或类似的东西,我怀疑是否有太多理由将它与fork结合使用。 It likely just provides broader portability for a "quick-exit" in other contexts. 它可能只是为其他环境中的“快速退出”提供了更广泛的可移植性。 That functionality is already covered by _exit() if you are using the POSIX API. 如果您使用的是POSIX API,则_exit()已涵盖该功能。

Program termination is addressed in C++2003 section [3.6.3]. 程序终止在C ++ 2003部分[3.6.3]中解决。 It says that static objects are destructed implicitly when main() returns and when exit() is called. 它表示当main()返回和调用exit()时,静态对象被隐式地破坏。 It also says that such objects are NOT destructed when abort() is called. 它还说当调用abort()时不会破坏这些对象。 _exit() isn't addressed in the C++ 2003 standard, but the fact that it is meant to bypass language-specific cleanup is described in the POSIX documentation. _exit()未在C ++ 2003标准中得到解决,但POSIX文档中描述了它旨在绕过特定于语言的清理的事实。 That effect is further substantiated by what is stated and by what is NOT stated in the C++ standard. 通过陈述的内容和C ++标准中未说明的内容进一步证实了这种效果。

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

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