在传统的 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() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章