将程序作为守护程序运行和使用“&”将其分叉到后台有什么区别?

use*_*108 52 shell process fork background-process daemon

在基于 Unix 的系统上部署服务时,从系统管理员的角度来看有哪些实际差异?

Sté*_*las 38

对于守护进程,您想要的是一个与任何事物都没有关系的进程。至少,你希望它在它自己的会话中,不附加到终端,没有从父级继承的任何文件描述符向任何东西开放,没有父级照顾你(除了 init)有当前的目录,/以免阻止卸载...

要从终端分离,您需要创建一个新会话,但是,要创建一个会话,您不能是组(或会话)领导者,因此最好是 fork 一个新进程。假设父进程退出,这也意味着该进程将不再有父进程并将被 init 采纳。然后,关闭所有可能的文件描述符,您chdir("/")(不能像文件描述符那样关闭当前工作目录以释放该资源,使/当前工作目录至少不会阻止卸载目录)。

因为那个进程是一个会话领导者,所以如果它打开一个终端设备,它就会成为那个终端的控制进程。第二次分叉确保它不会发生。

另一方面,& 在交互式 shell 中,fork 并创建一个新进程组(以免位于终端的前台进程组中),而在非交互式 shell 中,fork 一个进程并忽略其中的 SIGINT。它不会与终端分离,不会关闭文件描述符(尽管某些 shell 会重新打开 stdin 到/dev/null)...


Den*_*ker 32

传统的守护进程方式是:

fork()
setsid()
close(0) /* and /dev/null as fd 0, 1 and 2 */
close(1)
close(2)
fork()
Run Code Online (Sandbox Code Playgroud)

这确保该进程不再与终端在同一个进程组中,因此不会与其一起被杀死。IO 重定向是为了使输出不出现在终端上。

  • 请将 `&` 部分说明添加到您的答案中。它似乎不完整......如果你检查原始问题。 (12认同)
  • 当终端退出时,进程将收到 SIGHUP,该信号的默认处理程序是终止进程。 (9认同)
  • 因此,如果生成后台进程 (&) 的终端关闭,后台进程也将终止? (5认同)

小智 10

将程序/进程作为守护进程运行与使用与号将其分叉到后台之间的区别基本上与所有权有关。

大多数情况下,守护进程的父进程是init进程(在 Unix 系统上启动的第一个进程),守护进程作为该进程的子进程意味着它不受您作为非特权用户的直接控制. 另一方面,将程序/进程分叉到后台意味着您可以随时将其调用回前台和/或杀死它。


ZJR*_*ZJR 7

随着command &您的进程将在父进程死亡时被 SIGHUP 信号杀死。

不过,系统管理员可以访问一些解决方法。

在 bash 系统上,您可以使用:

(trap '' HUP; command) &
Run Code Online (Sandbox Code Playgroud)

这将打开一个子shell,HUP用一个空的处理程序捕获信号并与/分叉它。

输出可能仍会被重定向到错误的tty. 或者迷路。
你可以用&>command.out, 1>output.out, 或2>errors.out

在大多数系统上,您可能还可以访问该nohup命令。
nohup大大简化了这个过程。这是非常标准的,但我发现许多 busybox 嵌入式 ARM 发行版都缺少它。你只要写:

nohup command &
Run Code Online (Sandbox Code Playgroud)

..你完成了。输出被重定向,IIRC,到nohup.out,但可以使用选项更改此文件名。

  • 请注意,使用 ZSH,您可以稍后使用 `disown` 将 `command &` 与 shell 分离,然后作为 post-nohup 工作。 (2认同)