在这个答案顺便提到,守护进程使用init
双分叉并退出技巧重新调整自身父级是不合适的。答案链接到一个不再存在的网站但我在互联网档案馆找到了它。它列出了许多原因,归结为“您不应该进行守护进程,因为它可能会破坏init
或其他不期望守护进程的工具,如果有人以交互方式运行它,他们应该使用&
或nohup
明确要求后台运行。”实际上,这些原因听起来确实相当有说服力,因为正确配置的守护进程在收到控制权时应该已经在正常的环境中运行。 (嗯,理想情况下它运行在一个具有大量奇特自动化的容器中,但那是另一个故事了。)
但是,我不明白为什么我们有setsid(2)
如果我们不应该使用它。我能够了解setpgid(2)
;你需要它来实现一个(现代(ish))shell,但看起来像仅有的可靠调用的方法setsid(2)
是守护进程,手册页甚至告诉您这样做。我想您可能会使用它来实现最终运行的各种低级工具login(1)
,但setsid(2)
不是特权系统调用,并且其手册页没有提及此用例。至少,Python 人,似乎认为守护进程包括重新设置父级,而且我在许多其他环境中也看到过这种态度(特别是学术界,例如 PEP 引用的教科书)。
作为另一个参考点,daemonize(1)
和daemon(3)
是事物(在某些系统上),前者的手册页是这样说的:
大多数被设计为作为守护进程运行的程序都会为自己做[各种事情,包括重新设置父级]。但是,您偶尔会遇到不这样做的情况。当您必须运行一个无法正确地将自己变成真正的 Unix 守护程序的守护程序时,您可以使用 daemonize 强制它作为真正的守护程序运行。
守护进程在启动时的正确行为是什么,特别是它应该重新调整自身吗?
答案1
我一直认为setsid()
会议主持人与流程控制以及终端信号传输的工作原理有关。它们比流程组高一级。
Stackoverflow 上的答案指的是POSIX.1-2008,其中说:
3.339 会议
为作业控制目的而建立的过程组的集合。每个进程组都是会话的成员。进程被视为其进程组所属会话的成员。新创建的进程加入其创建者的会话。进程可以改变其会话成员身份;参见setsid()。同一会话中可以有多个进程组。
和第11章接下来讲述如何根据进程组和会话的控制终端传递信号。
实际上,我查看的 Linux 系统上所有逻辑上独立的“会话”都在单独的会话 id:s 下运行,因此login
或其他一些 ( sshd
, screen
) 确实按照您的建议运行setsid
。
至于守护进程应该做什么,我想这取决于使用什么 init 系统。在 Linux 上,使用传统的 System V 初始化脚本,守护进程必须自行进入后台(或在助手的帮助下)。尽管使用 sysvinit,初始化脚本可能会直接从管理员的 shell 运行,并且在所有情况下这可能都不是一个干净的环境。 (可以从会话继承资源限制等。)
在 Upstart 和 Systemd 上,如果守护进程不分叉自身可能会更好,因为 init 系统可以做到这一点。 (Upstart 特别做了一些有趣的事情跟随分叉守护进程。)
(我不知道其他 Unix,但正如 @Stephen Harris 所说评论了,守护程序支持分叉和不分叉行为可能是个好主意。)
还有eg ssh-agent
,它通常由用户自己运行,不需要init 系统的支持。它非常有用,它可以分叉到后台(使用setsid
)并保持活动状态,因此可以从多个 shell 中使用它。 (screen
windows,xterm
s...)它启动时也会有有用的输出,因此运行它nohup
会稍微复杂一些。
答案2
一个行为良好的守护进程应该将自身守护进程化,因为这是守护进程所期望的。即使守护进程不是从守护进程启动框架启动的,它也应该正常工作。
一个行为良好的守护进程应该有一个不守护进程的选项,以便可以从主管启动它。 (最新的 Linux 内核可以轻松监督双分叉的守护进程,但并非每个系统都运行最新的 Linux 内核,也不是每个监控程序都采用最新的 Linux 内核。)