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

ned*_*zha 50 c linux fork return exit

我一直试图弄清楚如何在Linux内部使用fork-exec机制.根据计划,一切都在继续,直到一些网页开始让我困惑.

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

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

维基百科和其他一些网页声称,我们必须使用_exit()它来防止子进程导致删除父进程的临时文件,同时可能会发生stdio缓冲区的双重刷新.虽然我理解前者,但我没有任何线索如何双重刷新缓冲区可能对Linux系统有害.

我花了一整天的时间......感谢任何澄清.

Fre*_*Foo 45

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

出于同样的原因,您还应该_exit在任何不执行此操作的子进程中使用exec,但这些进程很少见.

在所有其他情况下,只需使用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 ...
}
Run Code Online (Sandbox Code Playgroud)

  • @ ned1986zha:在`fork()`时,stdio缓冲区中可能有数据.如果父项和子项都刷新了这些缓冲区,则该数据将在输出中出现两次.如果`exec()`成功,问题就不存在了,因为在这种情况下,新执行的进程以新的stdio缓冲区开始. (5认同)
  • @ ned1986zha:是的 - `stdio`缓冲区是一个C库机制.可能还有操作系统提供的缓冲 - 但这并不重要,因为`fork()`不会复制它. (3认同)
  • @Bin:正如上面的评论所说,`_exit()`确保不刷新C库级(用户空间stdio)缓冲区 - 因为这些缓冲区被`fork()`复制(因为它们是用户空间,内核不知道它们).任何内核级缓冲区仍然会被刷新,但这没关系,因为`fork()`不会复制内核级缓冲区. (2认同)
  • @Bin:当进程被内核终止时,文件描述符将被关闭,但 stdio 缓冲区不会被刷新 - 因为内核对这些缓冲区一无所知,它们完全是用户空间 C 库的创建。 (2认同)

小智 16

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

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

有没有注意到这main()是一个功能?有没有想过首先叫它的是什么?当ac程序运行你运行的shell提供'exec'系统调用的可执行路径,并且控件被传递给内核,而内核又调用每个可执行文件的启动函数_start(),调用你的main(),当main()它返回它然后调用_end()C的一些实现使用略有不同的名称_end()&_start()...

exit()_exit()调用_end()

通常 - 每次main()应该只有一个exit()呼叫.(或在结束时返回main())

  • 不好,做个偷窃者不好。尊重别人的努力-&gt; #3 答案在那里-&gt; https://www.unix.com/programming/116721-difference-between-exit-_exit.html (7认同)

小智 5

exit() 位于 _exit() 之上,使用传统的 C 库。

有以下区别:

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

  2. _exit() 不能执行清理过程,而 exit() 可以注册一些函数(即 on_exit 或 at_exit)来执行一些清理过程,如果在程序存在之前需要的话。

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