为啥 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()