为什么在使用 setsid()
将进程变为守护进程之前需要使用 fork()
?
基本上,如果我想将一个进程与其控制终端分离并使其成为进程组领导者:我会使用 setsid()
。
如果在没有使用 fork()
的情况下执行此操作,则无法正常工作。
为什么呢?
首先: setsid()将使您的进程成为进程组领导者,但也将使您成为新会话的领导者。如果您只对获取自己的进程组感兴趣,则使用setpgid(0,0)。
现在,要理解为什么如果您已经是进程组领导者或会话领导者,则setsid()会返回EPERM,您必须了解进程组和会话ID是从创建它们(因此领导它们)的进程的进程ID初始化的(即对于会话领导者pid == sid,而对于进程组领导者pid == pgid)。此外,进程组无法在会话之间移动。
这意味着,如果您是进程组领导者,并且允许创建新会话,则sid和pgid将设置为您的pid,使旧进程组中的其他进程处于奇怪的状态:他们的进程组领导者突然处于不同的会话中,他们自己可能也是如此。这是不允许的,因此内核会返回EPERM错误。
现在,如果您fork()一次,则既不是会话领导者也不是进程组领导者,因此将您的sid和pgid设置为您的pid是安全的,因为在这样的组中没有其他进程。
所以,是的,想一想,这都有道理。
必须要使用 fork()
并且让子进程调用 setsid()
来确保调用 setsid()
的进程不是一个已经是进程组的领导者(setsid()
想要将其调用者设为一个新进程组的进程组领导者,因此在那种情况下会失败)。
man 2 setsid
命令时,你会得到以下描述:
setsid()
函数创建一个新会话和新进程组,则可能导致进程组 ID 冲突。 - zeekvfu