C ++ 11引入了一种完成程序执行的新方法 - std::quick_exit
。
引用N3242 18.5(第461页):
[[noreturn]] void quick_exit(int status) noexcept;
效果:调用
at_quick_exit
调用注册的函数 按照其注册的相反顺序,除了一个功能 应在任何先前已注册的职能之后召集 在注册时已被调用。物体不得 因调用quick_exit
而被销毁。如果控制离开了 由quick_exit
调用的注册函数,因为函数没有 为抛出的异常提供处理程序,应调用terminate()
。 [注意:at_quick_exit
可以从其他人处调用已注册的函数 线程比注册它的线程,所以注册函数应该 不依赖于具有线程存储持续时间的对象的身份。 - 结束注释]调用注册函数后,quick_exit
将调用_Exit(status)
。 [注意:标准文件缓冲区未刷新。见:ISO C 7.20.4.4。 - 结束说明]
由于std::abort(void)
和std::_Exit(int status)
的定义仅在将状态传递给父流程的能力上有所不同,因此它提出了我的问题。
这是否意味着std::quick_exit
和std::abort
之间语义的唯一区别是std::quick_exit
调用使用std::at_quick_exit
注册的函数并允许设置返回的状态?
引入此功能的理由是什么?
答案 0 :(得分:36)
有一篇很好的文章available here,我只是总结一下。添加此功能是为了专门处理使用线程时干净地结束程序的难度。本质上,退出是由高度异步的事件启动的,用户关闭用户界面,管理员关闭机器等等。这种情况发生时不考虑程序启动的线程状态,它们几乎总是处于高度不可预测的状态。
在理想的世界中,程序的main()函数要求线程退出,通常通过发出事件信号,等待线程结束然后退出main()以通过exit()进行干净关闭。然而,这种理想非常难以实现。线程可以深埋在系统调用内部,比如等待一些I / O完成。或者它是在需要由正确顺序的另一个线程发信号通知的同步对象上阻塞。结果很少令人愉快,真正的程序经常在退出时陷入僵局。或者在关机顺序意外时崩溃。
这个问题有一个简单且非常诱人的解决方法:调用_exit()代替。 Kaboom,程序结束,操作系统扫过弹片。但显然没有任何清理工作,有时会出现非常混乱的文件,例如半写文件或不完整的dbase事务。
std :: quick_exit()提供替代方案。与_exit()类似,但仍然可以选择执行某些代码,无论在at_quick_exit中注册了什么。
答案 1 :(得分:20)
std::quick_exit
和N1327讨论了quick_exit
的基本原理。 _Exit
,exit
和std::_Exit
之间的主要区别涉及静态析构函数的处理以及将关键信息刷新到稳定存储:
std::exit
:不执行静态析构函数或刷新关键IO。std::quick_exit
:执行静态析构函数并刷新关键IO。std::abort
:不执行静态析构函数,但会刷新关键IO。(如上所述,SIGABRT
只发送{{1}}。)
答案 2 :(得分:2)
std::abort
将终止您的应用程序而不调用使用“at_exit / at_quick_exit”注册的任何函数。另一方面,正如您所指出的,std::quick_exit
将调用使用std::at_quick_exit
注册的函数。
std::abort
通常中止您的应用程序,当发生某些异常情况并且您的应用程序必须关闭而不进行任何清理时,应调用此应用程序。来自std::abort
文档:
导致异常程序终止,除非SIGABRT被捕获 传递给signal的信号处理程序,处理程序不返回。
当您想要执行一些清理时,std::quick_exit
会更合适。最后一个函数还允许您优雅地停止应用程序,因为它最终调用std::_Exit
而不是发信号通知std::abort
这样的信号(它发出SIGABRT信号,使应用程序异常停止)。
std::exit
允许您正常退出应用程序,同时仍清除自动,线程本地和静态变量。 std::quick_exit
没有。这就是为什么它的名字中有一个“quick_”,它会更快,因为它会跳过清理阶段。
因此,两个函数之间存在实际的语义差异。一个人异常停止应用程序,另一个执行一个gracefull退出,允许你做一些清理。