为什么我注销后我的进程仍在运行?

为什么我注销后我的进程仍在运行?

通过 登录后ssh,我在 中输入此命令bash

sleep 50000000000000 &

然后我kill -9sleep进程的父进程(即bash)。然后终端窗口同时断开连接。

当我再次登录时,发现该sleep进程仍然存在。

问题:为什么sleep我注销并关闭终端时,进程可以存活?在我的认知中,nohup注销时除了守护进程和程序之外的所有进程都会被杀死。如果sleep这样可以存活,是不是意味着我可以用这种方法代替命令nohup

答案1

总结:

为什么sleep我注销并关闭终端时,进程还能存活?我的想法是,nohup注销时除了守护进程和程序之外的所有进程都会被杀死。如果sleep这样都能存活,是不是意味着我可以用这种方法代替命令nohup

除非bash由 生成的实例设置了ssh选项huponexit,否则在退出/注销时不会以任何方式终止任何进程,并且当huponexit设置了选项时,kill -9在 shell 上使用 并不是nohup在 shell 的子进程上使用的一个好选择;nohup在 shell 的子进程上仍然可以保护它们免受不是来自 shell 的 SIGHUP 的攻击,即使这并不重要,仍然nohup是首选,因为它允许 shell 正常终止。


bash一个名为的选项huponexit,如果设置了该选项bash,在退出/注销时将使其子进程发出 SIGHUP 信号;

在互动未登录 bash实例,例如bash由 生成的实例gnome-terminal,此选项将被忽略;无论是否huponexit设置,bash的子级在bash退出时都不会被 SIGHUP 触发;

在互动登录 bash实例,例如在bash由 生成的实例中ssh,此选项不会被忽略(但默认情况下未设置);如果huponexit设置了,则在退出/注销时,bash的子项将被 SIGHUP ;如果未设置,的子项在退出/注销时将不会被 SIGHUP ;bashhuponexitbashbash

因此,一般来说bash,除非设置了该huponexit选项,否则从交互式登录实例退出/注销不会使 shell SIGHUP 其子级,而从交互式非登录bash实例退出/注销无论如何都不会使 shell SIGHUP 其子级;

然而,在这种情况下,这并不重要:kill -9 sleep无论如何,使用都会存活下来,因为杀死它的父进程(bash)不会给后者留下机会去做任何事物到前者(例如,如果当前bash实例是登录bash实例并且huponexit设置了选项,则对其进行 SIGHUP)。

除此之外,与其他信号(例如发送到的SIGHUP信号bash)不同,SIGKILL信号永远不会传播到进程的子进程,因此sleep甚至不会被杀死;

nohup启动一个不受 SIGHUP 信号影响的进程,这是不同的东西;它将阻止进程在接收到 SIGHUP 信号时挂断,在这种情况下,bash如果huponexit设置了选项并且退出了 shell,交互式登录实例可以接收到该信号;所以从技术上讲,在交互式登录实例中使用未设置选项nohup来启动进程将阻止进程在接收到 SIGHUP 信号时挂断,但退出/注销 shell 无论如何都不会对其进行 SIGHUP ;bashhuponexit

然而,一般来说,当nohup需要阻止来自父 shell 的 SIGHUP 信号时,没有理由优先使用kill -9父方法而不是nohup子方法;相反,应该相反。

使用 方法来终止父进程,kill -9不会给父进程留下正常退出的机会,而使用nohup方法来启动子进程,则允许父进程通过其他信号来终止,比如 SIGHUP(举一个在使用 启动的子进程的上下文中有意义的例子nohup),这允许它正常退出。

答案2

bash默认情况下退出时不向子进程发送 HUP 信号。更详细(感谢@kos),它从来没有这样做过非登录 shell

您可以配置 bash 来执行此操作登录 shell如果设置了选项huponexit。在终端中,执行以下操作:

[romano:~] % bash -l

(这将启动一个新的“登录”shell)

romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout

现在检查该sleep过程:

[romano:~] % ps augx | grep sleep
romano   32231  0.0  0.0  16000  2408 pts/11   S+   15:23   0:00 grep sleep

...未运行:它已收到 HUP 信号并按请求退出。

答案3

如果sleep这样还能存活下来,是否意味着我可以用这个方法来代替nohup命令呢?

kill -9确实不是应该走的路。这就像用枪射击电视来关掉它。除了喜剧成分之外,没有任何好处。进程无法捕获或忽略SIGKILL。如果您不给进程一个机会来完成它正在做的事情并进行清理,它可能会留下损坏的文件(或其他状态)并且无法重新启动。kill -9当其他方法都不起作用时,这是最后的希望。


为什么当我注销并关闭终端时,睡眠进程还能存活下来。在我看来,注销时,除守护进程和 nohup 程序之外的所有程序都将被终止。

你的情况是这样的:

的父进程sleep是当前正在运行的bashshell。当您使用 bash 时,bash 进程没有机会向其任何子进程kill -9发送,因为发送的无法被进程捕获。sleep 进程继续运行。sleep 现在变成了SIGHUPSIGKILLkill -9孤儿进程

init (PID 1) 进程执行一种称为“重新指定父进程”的机制。这意味着 init 进程现在成为该孤立进程的父进程。init 是一个例外,当它收集失去其原始父进程的进程时,进程可以成为它的子进程。顺便说一句:守护进程(如sshd)在“进入后台”时会执行此操作。

如果不这样做,孤立进程稍后(完成后)将成为僵尸进程。这是在waitpid()未调用时发生的情况(父进程的责任,当该进程被终止时无法履行)。 initwaitpid()以特定的间隔调用以避免僵尸子进程。

答案4

使用&将导致程序在后台运行。要查看后台程序,请使用bg命令 ,要使其再次在前台运行,请运行fg

是的,即使主终端退出,也有很多方法可以让程序继续运行。

相关内容