为啥 fork() 在 setsid() 之前

Posted

技术标签:

【中文标题】为啥 fork() 在 setsid() 之前【英文标题】:Why fork() before setsid()为什么 fork() 在 setsid() 之前 【发布时间】:2011-02-06 11:20:38 【问题描述】:

为什么要在 setsid() 之前使用 fork() 来守护进程?

基本上,如果我想将一个进程与其控制终端分离并使其成为进程组负责人:我使用setsid()

在没有分叉的情况下这样做是行不通的。

为什么?

【问题讨论】:

【参考方案1】:

首先:setsid() 将使您的进程成为进程组的领导者,但它也会使您成为新会话的领导者。如果您只是对获取自己的进程组感兴趣,请使用 setpgid(0,0)。

现在要了解如果您已经是进程组负责人或会话负责人,setsid() 返回 EPERM 的实际原因,您必须了解进程组和会话 id 是从创建它们的进程的进程 id 初始化的(因此领先它们,即会话负责人 pid == sid 和进程组负责人 pid == pgid)。进程组也不能在会话之间移动。

这意味着,如果您是进程组负责人,并且允许创建新会话,则 sid 和 pgid 将设置为您的 pid,从而使旧进程组中的其他进程处于奇怪的状态:他们的进程组长突然与他们自己可能处于不同的会话中。这是不允许的,因此内核使用了 EPERM。

现在如果你 fork() 一旦你既不是会话也不是进程组负责人,因此将你的 sid 和 pgid 设置为你的 pid 是安全的,因为这样的组中没有其他进程。

所以,是的,想想看,这一切都说得通。

【讨论】:

能否请您提供一些参考文档来解释该流程是流程组领导者的含义,以及为什么这很重要。 如果允许进程组组长调用setsid(),创建新会话和新进程组,可能会导致进程组id冲突。【参考方案2】:

需要fork() 并让子调用setsid() 以确保调用setsid() 的进程还不是进程组组长(setsid() 想让调用进程成为进程组组长new 进程组,因此在这种情况下它会失败)。

【讨论】:

【参考方案3】:

man 2 setsid,你会得到如下描述:

setsid() 如果调用进程不是进程组领导,则创建一个新会话。调用进程是新会话的leader,新进程组的进程组leader,没有控制终端。调用进程的进程组 ID 和会话 ID 设置为调用进程的 PID。调用进程将是这个新进程组和这个新会话中的唯一进程。

如果允许进程组负责人调用setsid(),创建一个新的会话和一个新的进程组(具有相同的进程组id),会导致进程组id冲突。

【讨论】:

以上是关于为啥 fork() 在 setsid() 之前的主要内容,如果未能解决你的问题,请参考以下文章

在 posix_spawn() 创建的过程中调用 setsid()

为啥在调用 c++ fork 函数之前创建的值没有被父进程和子进程修改两次?

队列和栈

PHP进程管理

如何创建守护进程?

为啥我的 fork 子进程在我 fork 后立即退出?