我退出后为什么我的进程仍在运行?
通过ssh
,我在bash
输入以下命令:
sleep 50000000000000 &
然后我kill -9
sleep
过程的父进程(即bash
)。 然后终端窗口同时断开。
当我再次登录时,我发现sleep
过程仍然存在。
问题 :当我退出并关闭终端时,为什么sleep
过程能够存活? 在我看来,除了守护进程和nohup
程序之外的所有东西都会在注销时被杀死。 如果sleep
能够以这种方式存活,这是否意味着我可以使用此方法而不是nohup
命令?
TL;博士:
当我退出并且终端关闭时,为什么
sleep
过程能够存活? 在我看来,除了守护进程和nohup
程序之外的所有东西都会在注销时被杀死。 如果sleep
能够以这种方式存活,这是否意味着我可以使用此方法而不是nohup
命令?
除非ssh
生成的bash
实例设置了huponexit
选项,否则在退出/退出时任何进程都不会终止任何进程,并且当设置huponexit
选项时,在shell上使用kill -9
不是使用nohup
的好选择关于shell的子进程; 关于shell的子进程的nohup
仍将保护它们不受来自shell的SIGHUP的影响,即使这不重要, nohup
仍然是首选,因为它允许shell优雅地终止。
在bash
有一个名为huponexit
的选项,如果设置将在退出/注销时将bash
SIGHUP作为子huponexit
;
在交互式非登录 bash
实例中,例如在gnome-terminal
生成的bash
实例中,忽略此选项; 无论huponexit
是设置还是未设置, bash
的子节点在退出时都不会受到bash
影响;
在交互式登录 bash
实例中,例如在ssh
生成的bash
实例中,不会忽略此选项(但默认情况下未设置此选项); 如果设置了huponexit
, bash
的子节点将在退出/注销时被bash
大写; 如果没有设置huponexit,退出/注销时bash
的子节点不会被bash
强行;
因此,通常从交互式登录bash
实例退出/注销,除非设置了huponexit
选项,否则不会使shell SIGHUP成为子huponexit
,并且从交互式非登录bash
实例退出/注销将不会使shell成为shell无论如何,它的孩子都要大声说
然而,在这种情况下,这是无关紧要的:使用kill -9
sleep
无论如何都会存活,因为杀死它的父进程( bash
)不会让后者对前者做任何事情 (例如,如果当前bash
实例是一个登录bash
实例,并且huponexit
选项已设置为SIGHUP()。
除此之外,与其他信号(如发送给bash
的SIGHUP信号)不同,SIGKILL信号永远不会传播到进程的子进程,因此甚至不会杀死sleep
;
nohup
启动一个免受SIGHUP信号影响的过程,这是不同的东西; 它会阻止进程在接收到SIGHUP信号时挂起,在这种情况下,如果设置了huponexit
选项并退出shell,则交互式登录bash
实例可以接收该信号; 因此,技术上使用nohup
在交互式登录bash
实例中启动进程并且huponexit
设置huponexit
选项将阻止进程在接收到SIGHUP信号时挂起,但是退出/退出shell将不会对其进行SIGHUP;
但是,一般情况下,当需要nohup
来防止来自父shell的SIGHUP信号时,没有理由更喜欢父方法上的kill -9
和子方法上的nohup
; 相反,它应该是相反的。
使用kill -9
方法kill -9
父级并不会让父级正常退出,而使用nohup
方法启动子级允许父级被其他信号终止,例如SIGHUP(举个例子来说明在孩子的情境中感觉开始使用nohup
),这允许它优雅地退出。
默认情况下, bash
在退出时不会将HUP信号发送到子进程 。 更详细(谢谢@kos),它永远不会用于非登录shell 。
如果设置选项huponexit
则可以配置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信号并按要求退出。
如果
sleep
可以通过这种方式存活,如果这意味着我可以使用此方法而不是nohup
命令?
kill -9
真的不是应该去的方式。 就像在电视机上用枪射击将其关闭一样。 除了喜剧成分之外没有任何优势。 进程无法捕获或忽略SIGKILL
。 如果你没有让进程有机会完成正在进行的操作和清理,它可能会留下损坏的文件(或其他状态),并且无法再次启动。 kill -9
是最后的希望,没有别的办法。
当我退出并关闭终端时,为什么睡眠过程可以存活。 在我看来,除了守护进程和nohup程序之外的所有东西都会在注销时被杀死。
在你的情况下发生什么:
sleep
的父进程是当前运行的bash
shell。 当你kill -9
那个bash时,bash进程没有机会向其任何子进程发送SIGHUP
,因为进程无法捕获SIGKILL
(由kill -9
发送)。 睡眠过程继续运行。 睡觉现在成了一个孤儿过程 。
init(PID 1)进程执行一种称为重新定位的机制。 这意味着init进程现在成为该孤立进程的父进程。 init是一个例外,进程可以成为它的子进程,因为它收集丢失原始父进程的进程。 顺便说一句:一个守护进程(如sshd
)在“在后台进行”时sshd
。
如果不会发生这种情况,孤立的进程将在稍后(完成后)成为僵尸进程。 这是在未调用waitpid()
时发生的情况waitpid()
父进程的责任,当该进程被杀死时无法完成填充)。 init在特定的intervall中调用waitpid()
以避免僵尸孩子。
&
在后台启动该过程。 如果输入ps -ef
,您将看到睡眠的父进程ID(PPID)是您的bash。 然后注销并再次登录。 在您注销后,该过程将继续运行。 第二次登录后再次运行ps -ef
。 您将看到现在睡眠过程的父进程将以id为“1”进行处理。 这是init,所有进程的父级。
使用&
将导致程序作为背景运行。 要在后台使用bg
命令查看程序,并使其再次作为前台运行,请运行fg
。
是的,即使主终端退出,也有很多方法可以让程序保持运行。