在传统的 Linux fork-exec 中使用 _exit() 和 exit() 有啥区别?

Posted

技术标签:

【中文标题】在传统的 Linux fork-exec 中使用 _exit() 和 exit() 有啥区别?【英文标题】:What is the difference between using _exit() & exit() in a conventional Linux fork-exec?在传统的 Linux fork-exec 中使用 _exit() 和 exit() 有什么区别? 【发布时间】:2011-07-22 07:47:26 【问题描述】:

我一直试图弄清楚 fork-exec 机制是如何在 Linux 中使用的。一切都按计划进行,直到一些网页开始让我感到困惑。

据说子进程应该严格使用_exit(),而不是简单的exit()或者从main()正常返回。

据我所知,Linux shell fork-exec 会执行每一个外部命令;假设我上面说的是真的,那么结论是这些外部命令和Linux shell内部发生的任何其他执行都不能正常返回!

Wikipedia 和其他一些网页声称我们必须使用 _exit() 只是为了防止子进程导致删除父进程的临时文件,同时可能会发生 stdio 缓冲区的双重刷新。虽然我理解前者,但我不知道缓冲区的双重刷新如何对 Linux 系统有害。

我已经花了一整天的时间... 感谢您的澄清。

【问题讨论】:

***.com/questions/2329640/… 的副本。也相关:***.com/questions/3657667/exit-functions-in-c 【参考方案1】:

您应该使用_exit(或其同义词_Exit)在exec失败时中止子程序,因为在这种情况下,子进程可能会干扰父进程的外部数据(文件)调用其atexit 处理程序、调用其信号处理程序和/或刷新缓冲区。

出于同样的原因,您还应该在任何不执行exec 的子进程中使用_exit,但这种情况很少见。

在所有其他情况下,只需使用exit。正如您自己部分指出的那样,Unix/Linux 中的 每个 进程(除了一个,init)是另一个进程的子进程,因此在每个子进程中使用 _exit 意味着 exit 是在init之外没用。

switch (fork()) 
  case 0:
    // we're the child
    execlp("some", "program", NULL);
    _exit(1);  // <-- HERE
  case -1:
    // error, no fork done ...
  default:
    // we're the parent ...

【讨论】:

TONS 感谢。我现在感觉好多了;虽然两次刷新缓冲区仍然存在问题,但对我来说没有意义。 @ned1986zha:fork() 时,stdio 缓冲区中可能有数据。如果父级和子级都刷新这些缓冲区,则该数据将在输出中出现两次。如果exec() 成功,则问题不存在,因为在这种情况下,新执行的进程从新的 stdio 缓冲区开始。 @ned1986zha:是的 - stdio 缓冲区是一种 C 库机制。也可能有操作系统提供的缓冲——但这没关系,因为fork() 不会复制。 @Bin:正如上面的 cmets 所说,_exit() 确保不会刷新 C 库级别(用户空间 stdio)缓冲区 - 因为这些缓冲区被 fork() 复制(因为它们'是用户空间,内核不知道它们)。任何内核级缓冲区仍会被刷新,但这没关系,因为fork() 不会复制内核级缓冲区。 @Bin: 当进程被内核终止时,文件描述符被关闭但 stdio 缓冲区没有被刷新——因为内核对这些缓冲区一无所知,它们完全创建用户空间 C 库。【参考方案2】:

exit() 刷新 io 缓冲区并执行其他一些操作,例如运行 atexit() 注册的函数。 exit() 调用 _end( )

_exit() 只是结束该过程而不这样做。例如,在创建守护进程时从父进程调用_exit()

有没有注意到main() 是一个函数?有没有想过首先叫它什么? 当 ac 程序运行时,您正在运行的 shell 提供“exec”系统调用的可执行路径,并将控制权传递给内核,内核依次调用每个可执行文件 _start() 的启动函数,调用您的 main(),当 @987654331 @ 返回它然后调用 _end() 一些 C 的实现对 _end()_start() 使用略有不同的名称 ...

exit()_exit() 调用 _end()

通常 - 对于每个 main(),应该只有一个 exit() 呼叫。 (或在main()末尾返回)

【讨论】:

不好,偷东西不好。尊重别人的努力 -> #3 答案在那里 -> unix.com/programming/116721-difference-between-exit-_exit.html【参考方案3】:

exit() 在 _exit() 的顶部,使用传统的 C 库。

有区别:

    _exit() 不会刷新 stdio 缓冲区,而 exit() 在退出之前会刷新 stdio 缓冲区。

    _exit() 无法执行清理过程,而 exit() 可以注册到某些函数(即 on_exit 或 at_exit)以执行某些清理过程,如果 在存在程序之前需要任何东西。

exit(status) 只是将退出状态传递给 _exit(status)。建议无论何时执行fork(),其中一个在child和parent之间,一个使用_exit(),另一个使用exit()。

【讨论】:

【参考方案4】:

fork()的子分支中,通常使用不正确 exit(),因为这会导致 stdio 缓冲区被刷新两次, 和临时文件被意外删除。

摘自:http://www.unixguide.net/unix/programming/1.1.3.shtml

【讨论】:

以上是关于在传统的 Linux fork-exec 中使用 _exit() 和 exit() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Linux搭建图片服务器减轻传统服务器的压力(nginx+vsftpd)

SELinux的主要作用简介

Linux上Python系统范围的互斥体

linux系统的语言编码设置字体

Zipkin 用于分析传统程序的内部结构

Linux - 不同桌面环境