HUP信号什么时候停止发送,我该怎么办?

12

回到我年轻时,Unix还是新鲜事物的时候,创建一个不会在你注销后被终止的进程是一项挑战。我们使用nohup命令来保护我们的持久性进程免受HUP信号的影响。如果我们不小心,我们的进程将在我们注销或甚至关闭启动它们的shell时被终止。

快进到今天,我发现默认情况似乎完全相反。在Ubuntu和Red Hat系统上,我发现我可以将几乎任何进程放在后台,杀死父shell,注销,甚至关掉窗口,它仍然可以继续运行。我在Bash脚本、Python脚本和C程序中看到了相同的行为。我从xterm或ssh会话中也得到了相同的行为。

例如,在xterm或ssh窗口中输入:

while [ 1 ]; do date; sleep 10; done > /tmp/out &

现在从另一个窗口运行

tail -f /tmp/out

每隔10秒钟打印日期,然后使用Ctrl-D关闭原始父shell。仍在运行。退出并重新登录。仍在运行。

发送HUP信号,它会立即停止。

我可以用Python脚本或C程序展示相同的行为。无论是否睡眠都没有关系。例如,这个丑陋的C程序表现相同:

#include <stdio.h>

void main() {
    while(1) {
        printf("*\n");
        fflush(stdout);
        int i, j, k = 0;
        for(i=0; i < 10000; i++) {
            for(j=0; j < 100000; j++) {
                k += i * j;
            }
        }
    }
}

这完全违背了我年轻时候的方式。也许当它改变时我只是没有注意到?有没有历史学家知道这是什么时候发生的?现在还有人使用HUP吗?

如果确实是当前情况,我的问题是:如何安排一个进程在用户注销或断开连接时自动退出?

我有一个方法,涉及观察ppid(父进程ID)的变化,但肯定有比那更优雅的方法。


huponexit是bash选项https://dev59.com/Z2855IYBdhLWcg3wg0rC - JimB
2个回答

7

我相信您正在寻找关于huponexit命令的相关内容,您可以通过以下方式轻松设置:

$ shopt -s huponexit

以下是bash手册中的一些细节:

默认情况下,Shell在收到SIGHUP时退出。在退出之前,交互式Shell会重新发送SIGHUP给所有正在运行或停止的作业。停止的作业会收到SIGCONT以确保它们接收到SIGHUP。要防止Shell向特定作业发送信号,应使用disown内置命令(请参见下面的Shell内置命令)将其从作业表中移除或使用disown -h将其标记为不接收SIGHUP。

如果已经使用shopt设置了huponexit Shell选项,则当交互式登录Shell退出时,bash会向所有作业发送SIGHUP。


这个选项似乎解释了我意外地发现的xterms和ssh的行为。谢谢! - GaryBishop

4

我仍然会收到SIGHUP信号。一个简单的测试方式:

#!/usr/bin/env sh

echo "$$"
trap "echo HUPPED $$ > /tmp/willithup" HUP
sleep 1000

然后关闭终端仿真器。现在回到你的问题:
观察它每10秒打印一次日期,然后使用Ctrl-D关闭原始父shell。仍在运行。注销并重新登录。仍在运行。
当进程失去与控制终端的连接或显式发送HUP时,进程不会收到HUP。例如,当您注销SSH时会发生这种情况。
对于第二个问题:当shell退出时,shell本身可以向其所有子进程发送HUP。但是,默认情况下,bash将huponexit设置为false。这可能是发生了什么变化。请注意,无论huponexit选项如何,当shell接收到HUP时,它也会向其所有子进程发送HUP。
斯蒂文斯的话:
会话可以有一个控制终端。这通常是我们登录的终端设备(在终端登录的情况下)或伪终端设备(在网络登录的情况下)。
如果终端接口检测到调制解调器(或网络)断开连接,则发送挂起信号给控制进程(会话领导者)。
进一步澄清,初始HUP不是由shell发送的。它由终端驱动程序发送。之后,shell将其“转发”给子级。因此,由终端驱动程序发送的HUP可以“级联”。从TLPI:
当控制进程失去其终端连接时,内核向其发送SIGHUP信号以通知其此事实。 (还发送SIGCONT信号,以确保如果进程先前被信号停止,则重启该进程。)通常,这可能出现两种情况:
当终端驱动程序检测到“断开”时,表示调制解调器或终端线路信号丢失。
在工作站上关闭终端窗口时。这是因为与终端窗口关联的伪终端的主端的最后一个打开文件描述符已关闭。

我不确定在关闭终端模拟器之前是否将其放入后台。这个问题涉及到在后台运行的进程。 - GaryBishop
@GaryBishop 你可以在“后台”运行它。只有当它失去与终端界面的连接时,它才会始终收到HUP信号。 - cnicutar
@JimB 我已经添加了一句引用来自TLPI :-) - cnicutar
@cnicutar 所说皆属实,但我认为 OP 指的是 shell 本身在退出时向所有子进程发送 HUP 的常见行为。 - JimB
@GaryBishop 这非常有趣。你使用的是哪个Linux?Bash版本是多少?你如何测试以确保不会收到HUP信号? - cnicutar
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接