双叉() - 为什么?

双叉() - 为什么?

我在源码中发现了如下函数猫眼(简约的窗口管理器):

void spawn(const Arg arg) {
    if(fork() == 0) {
        if(fork() == 0) {
            if(dis)
                close(ConnectionNumber(dis));

            setsid();
            execvp((char*)arg.com[0],(char**)arg.com);
        }
        exit(0);
    }
}

在 github 上看到它

我不明白为什么不简单地

void spawn(const Arg arg) {
    if(fork() == 0) {
        if(dis)
            close(ConnectionNumber(dis));

        setsid();
        execvp((char*)arg.com[0],(char**)arg.com);
    }
}

?在这里使用 double 有什么好处吗fork()

答案1

以下段落,引自 Stevens 和 RagoUNIX 环境中的高级编程,描述编写守护程序的六个编码规则中的两个。具体来说,他们在图 13.1 中列出的单个daemonize函数中实现了它们,以防您想查找它。

  1. 调用 fork 并让父级退出。这有几件事。首先,如果守护进程作为简单的 shell 命令启动,则让父进程终止会使 shell 认为该命令已完成。其次,子进程继承父进程的进程组 ID,但获得一个新的进程 ID,因此我们可以保证子进程不是进程组领导者。这是接下来调用setsid 的先决条件。
  2. 调用setsid创建一个新会话。发生第 9.5 节中列出的三个步骤。进程 (a) 成为新会话的领导者,(b) 成为新进程组的领导者,并且 (c) 与其控制终端解除关联。
    • 在基于 System V 的系统下,有些人建议在此时再次调用 fork,终止父进程,并继续子进程中的守护进程。这保证了守护进程不是会话领导者,从而阻止它根据 System V 规则获取控制终端(第 9.6 节)。或者,为了避免获取控制终端,请确保在打开终端设备时指定 O_NOCTTY。

在您更改的代码中,父级不会,它将在调用exit()后继续执行;spawn()确切的行为取决于spawn()调用后的内容。

相关内容