<p>严格地说,double fork与将守护进程重新作为<code>init</code>的子进程无关。要使子对象重新成为父对象,只需要父对象必须退出。这只能用一把叉子。此外,单独执行double fork不会使守护进程成为<code>init</code>的父进程;守护进程的父进程必须退出。换言之,当派生一个合适的守护进程时,父进程始终存在,以便守护进程重新成为<code>init</code>的父进程。</p>
<p>那为什么要用双叉呢?<a href="http://pubs.opengroup.org/onlinepubs/9699919799/toc.htm" rel="noreferrer">POSIX.1-2008</a>第11.1.3节,“<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html#tag_11_01_03" rel="noreferrer">The Controlling Terminal</a>”给出了答案(添加了重点):</p>
<blockquote>
<p>The controlling terminal for a session is <strong>allocated by the session leader</strong> in an implementation-defined manner. If a session leader has no controlling terminal, and opens a terminal device file that is not already associated with a session without using the <code>O_NOCTTY</code> option (see <code>open()</code>), it is implementation-defined whether the terminal becomes the controlling terminal of the session leader. If a process which is <strong>not a session leader</strong> opens a terminal file, or the <code>O_NOCTTY</code> option is used on <code>open()</code>, <strong>then that terminal shall not become the controlling terminal of the calling process</strong>.</p>
</blockquote>
<p>这告诉我们,如果一个守护进程执行类似的操作。。。</p>
<pre><code>int fd = open("/dev/console", O_RDWR);
</code></pre>
<p>。。。然后,守护进程<em>可能会</em>获取<code>/dev/console</code>作为其控制终端,这取决于守护进程是否是会话领导者,也取决于系统实现。如果程序首先确保它不是会话领导者,则程序可以保证上述调用不会获得控制终端。</p>
<p>通常,在启动守护进程时,会调用<code>setsid</code>(在调用<code>fork</code>之后从子进程中)来将守护进程与其控制终端分离。然而,调用<code>setsid</code>也意味着调用进程将成为新会话的会话领导者,这使得守护进程有可能重新获取控制终端。double-fork技术确保守护进程不是会话领导者,从而保证对<code>open</code>的调用(如上面的示例所示)不会导致守护进程重新获取控制终端。</p>
<p>双叉技术有点偏执。如果您知道守护进程永远不会打开终端设备文件,则可能不需要这样做。此外,在某些系统上,即使后台程序确实打开了终端设备文件,也可能不需要,因为该行为是由实现定义的。但是,有一件事不是实现定义的,那就是只有会话负责人可以分配控制终端。<strong>如果进程不是会话引导者,则它无法分配控制终端。</strong>因此,如果您想变得多疑,并确保守护进程不会无意中获取控制终端,而不管实现定义了什么细节,那么双分叉技术是必不可少的。</p>