我试图在python中创建一个守护进程。我发现了下面的问题,其中有一些很好的资源,我目前正在关注,但我很好奇为什么需要双分叉。我对谷歌进行了研究,发现了大量的资源,这些资源都表明这是必要的,但不知道为什么。

有人提到这是为了防止守护进程获取控制终端。如果没有第二个分叉,它将如何做到这一点?后果是什么?


当前回答

关于它的一个像样的讨论似乎在http://www.developerweb.net/forum/showthread.php?t=3025上

引用mlampkin的话:

...将setsid()调用视为做事的“新”方式(与终端分离),而[第二个]fork()调用作为处理SVr4的冗余…

其他回答

摘自Bad CTK:

在某些类型的Unix上,为了进入守护进程模式,你不得不在启动时执行双叉操作。这是因为单分叉不能保证与控制终端分离。”

如果daemon()调用成功,则有父调用_exit()。最初的动机可能是让父母在孩子守护的时候做一些额外的工作。

这也可能是基于一种错误的信念,认为这是必要的,以确保守护进程没有父进程,并被重新父化给init——但在单分叉的情况下,一旦父进程死亡,无论如何都会发生这种情况。

所以我认为这一切最终都归结为传统——只要父母在短时间内死亡,一个分叉就足够了。

根据Stephens和Rago的“Unix环境中的高级编程”,第二个fork更多的是一个建议,它是为了保证守护进程不会在基于System v的系统上获得控制终端。

查看问题中引用的代码,理由是:

Fork a second child and exit immediately to prevent zombies. This causes the second child process to be orphaned, making the init process responsible for its cleanup. And, since the first child is a session leader without a controlling terminal, it's possible for it to acquire one by opening a terminal in the future (System V- based systems). This second fork guarantees that the child is no longer a session leader, preventing the daemon from ever acquiring a controlling terminal.

因此,这是为了确保守护进程被重新父化到init上(以防启动守护进程的进程是长期存在的),并消除守护进程重新获得控制tty的任何机会。因此,如果这两种情况都不适用,那么一个分叉就足够了。“Unix网络编程- Stevens”在这方面有一个很好的章节。

一个原因是父进程可以立即为子进程wait_pid(),然后忘记它。当孙子孙女死亡时,它的父节点是init,它将wait()等待它——并将它从僵尸状态中取出。

结果是,父进程不需要知道被分叉的子进程,这也使得从库等中分叉长时间运行的进程成为可能。