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,除非出现不可恢复的错误,否则不要调用exitraise @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的应用

为啥我的程序没有收到 SIGTERM?

Python subprocess + timeout的命令执行

Python之异常处理

Nodejs 进程信号

确保 spring boot 和 liquibase 接收和处理 SIGTERM