exit(0) 和 raise(SIGTERM) 有啥区别
Posted
技术标签:
【中文标题】exit(0) 和 raise(SIGTERM) 有啥区别【英文标题】:What is the difference between exit(0) and raise(SIGTERM)exit(0) 和 raise(SIGTERM) 有什么区别 【发布时间】:2020-06-09 23:20:17 【问题描述】:我试图在某些特定事件上终止我的应用程序。为什么一个会使用 exit(0) 或 raise(SIGTERM) 而不是另一个?
另外,由于 exit(0) 将 EXIT_SUCCESS 返回给主机,SIGTERM 有什么作用?总是失败吗?
【问题讨论】:
@William Pursell 你可能知道答案.. 既然您标记为 C++,您应该查看try/catch/throw
,这是 C++ 中内置的异常机制。
@NikitaP raise
从未使用过,因为它不可移植。 C 标准有以下内容:“完整的信号集、它们的语义和它们的默认处理是实现定义的”.
作为参考,Apple 指南规定应用程序永远不应自愿终止。 IE,除非出现不可恢复的错误,否则不要调用exit
或raise
。
@user3386109 “完整集”是“实现定义”,但 raise()
和 SIGTERM
符合标准 C。仍然使用 raise(SIGTERM)
而不是 exit()
或简单地使用 return
来自main()
是一个非常糟糕的主意。
【参考方案1】:
exit
导致程序以正常退出状态终止,其值由exit
的参数给出,在您的情况下为 0。
raise
发出一个信号,可能会被捕获。如果它没有被捕获或阻止,则执行默认操作。对于SIGTERM
,默认动作是异常终止,导致它的信号在程序的退出状态中可见。
这对 ios 应用程序有什么影响,我不确定。
【讨论】:
谢谢 是否有偏好,为什么? 除非您的程序遇到需要退出的错误情况,否则您应该始终以成功退出状态退出,通过exit(0)
或仅从main
返回 0。 raise(SIGTERM)
几乎没有任何理由。听起来你对这门语言不是很熟悉,所以我很困惑你在哪里了解了 raise
,这在 iOS 和大多数情况下可能完全没用和不合适,除了某些类型的系统编程。
@NikitaP:如果您的程序正常退出,请使用exit(0)
或exit(EXIT_SUCCESS)
。如果您的程序遇到错误,它想向调用它的事物报告,但它可以正常退出,请使用exit(EXIT_FAILURE)
或exit
的其他状态。如果您的程序遇到严重错误无法正常退出,请使用abort()
。这在正常应用中是不需要的;它可能会丢失文件缓冲区中的待处理数据。通常不需要使用raise(SIGTERM)
,除非您的程序已经出于其他原因处理信号并且您希望为此绑定代码。
@ThomasMatthews:从main
返回可能会很浪费。它可能需要通过正常的函数返回,这可能会执行诸如释放动态分配的内存之类的事情。但是这样做会调用free
,它将释放的内存记录在内部数据结构中,这些数据结构可能分散在整个内存中,这会更改页面,这可能会导致交换,导致进程在尝试退出时暂停几秒钟。直接调用exit
将刷新缓冲区并终止,避免不必要的取消分配内存的簿记,无论如何都会被擦除。
@NikitaP 你是从哪里了解到raise
的?为什么你认为应该使用它?【参考方案2】:
默认情况下发送raise( SIGTERM )
会导致“异常终止”,这意味着在正常程序终止中完成的许多事情都没有完成。根据C 11 standard's 7.22.4.4 The exit function
说明
2
exit
函数导致程序正常终止。不 由at_quick_exit
函数注册的函数被调用。如果一个 程序多次调用exit
函数,或调用quick_exit
函数除了exit
函数,行为是 未定义。3 首先调用
atexit
函数注册的所有函数, 以他们注册的相反顺序,除了一个函数 在任何先前注册的函数之后调用 在注册时被调用。如果,在调用任何 这样的函数,调用longjmp
函数将 终止对注册函数的调用,行为是 未定义。4 接下来,所有带有未写入缓冲数据的打开流都被刷新,所有 打开的流被关闭,
tmpfile
函数创建的所有文件 被删除。5 最后,控制权返回到宿主环境。 ...
如果你调用raise(SIGTERM)
,这一切都不会发生,除非你添加一个信号处理程序,它会以某种方式调用exit()
。请注意,您不能简单地从信号处理程序中直接调用 exit()
,因为 exit()
函数不是异步信号安全的。
请特别注意“所有带有未写入缓冲数据的打开流都将被刷新”。如果不这样做,您可能会丢失数据。
并且,如上所述,您的程序创建的任何临时文件都不会被清理。
在 C++ 代码中,具有static
存储持续时间的对象在标准程序终止中被销毁。在raise( SIGTERM )
引起的异常终止中不会发生这种情况。因此,这些对象在其析构函数中执行的任何清理操作都不会完成。
【讨论】:
以上是关于exit(0) 和 raise(SIGTERM) 有啥区别的主要内容,如果未能解决你的问题,请参考以下文章
Go语言-信号os.Interrupt和信号syscall.SIGTERM的应用