我有一个嵌入式系统,在上面执行telnet,然后在后台运行应用程序:

./app_name &

现在,如果我关闭终端并在其他终端上执行telnet,并且进行检查,则可以看到此过程仍在运行。

为了检查这一点,我编写了一个小程序:

#include<stdio.h>
main()
{
    while(1);
}

我在后台在本地linux PC中运行了该程序,然后关闭了终端。

现在,当我从其他终端检查此过程时,我发现该过程也被杀死。

我的问题是:
  • 为什么相同类型进程的行为不确定?
  • 取决于哪个?
  • 它取决于Linux版本吗?
  • 最佳答案

    谁应该杀死工作?

    通常,前台和后台作业在不同情况下会被内核或 shell 程序发送的SIGHUP杀死。

    内核何时发送SIGHUP

    内核将SIGHUP发送到controlling process:

    真实(硬件)终端的

  • :在终端驱动程序中检测到断开连接时,例如挂断调制解调器线路时;
  • pseudoterminal(pty)的
  • :关闭引用pty主端的最后一个描述符时,例如当您关闭终端窗口时。

  • 内核将SIGHUP发送到其他进程组:

    当控制进程终止时,
  • 到前台进程组;
  • orphaned process group,当它成为孤立的并且已停止成员时。



  • 通常,控制过程是您的 shell 。因此,总结一下:

    当真正或伪终端断开/关闭时,
  • 内核将SIGHUP发送到 shell ;
  • shell 终止时,
  • 内核将SIGHUP发送到前台进程组。
  • 如果
  • 内核包含停止的进程,则它将SIGHUP发送到孤立的进程组。

  • 请注意,如果内核不包含停止的进程,则它不会将SIGHUP发送到后台进程组。
    bash何时发送SIGHUP

    Bash将SIGHUP发送到所有作业(前景和背景):
  • 收到SIGHUP时,它是一个交互式 shell 程序(并且在编译时启用了作业控制支持);
  • 退出时,它是一个交互式登录 shell ,并且设置了huponexit选项(并且在编译时启用了作业控制支持)。

  • 查看更多详细信息here

    笔记:
  • bash不会将SIGHUP发送到使用disown从作业列表中删除的作业;
  • 使用nohup开始的
  • 进程忽略SIGHUP

  • 更多详细信息here

    那其他 shell 呢?

    通常,shell传播SIGHUP。在普通导出生成SIGHUP的情况比较少见。

    Telnet或SSH

    在telnet或SSH下,关闭连接时(例如,在PC上关闭telnet窗口时)将发生以下情况:
  • 客户端被杀死;
  • 服务器检测到客户端连接已关闭;
  • 服务器关闭pty的主服务器端;
  • 内核检测到主pty已关闭,并将SIGHUP发送到bash
  • bash接收SIGHUP,将SIGHUP发送给所有作业并终止;
  • 每个作业都会收到SIGHUP并终止。


  • 问题

    我可以使用bashtelnetd SSH服务器上的busyboxdropbear重现您的问题:有时,关闭客户端连接后,后台作业不会收到SIGHUP(并且不会终止)。

    当服务器(telnetddropbear)关闭pty的主服务器端时,似乎出现竞争条件:
  • 通常,bash接收SIGHUP并立即终止后台作业(如预期的那样)并终止;
  • ,但有时bash在处理EOF之前会检测pty的从属端上的SIGHUP

  • bash检测到EOF时,默认情况下它将立即终止而不发送SIGHUP。后台作业仍在运行!



    也可以将bash配置为在正常导出(包括SIGHUP)上发送EOF:
  • 确保bash作为登录shell启动。 huponexit works仅用于登录 shell AFAIK。

    登录 shell 通过-l中的argv[0]选项或leading hyphen启用。您可以配置telnetd来运行/bin/bash -l或更好的/bin/login,后者在登录Shell模式下调用/bin/sh

    例如。:

    telnetd -l/bin/登录
  • 启用huponexit选项。

    例如。:

    shopt -s huponexit

    每次在bash session 中键入此内容,或将其添加到.bashrc/etc/profile中。


  • 种族为什么会发生?
    bash仅在安全时取消阻止信号,并在信号处理程序无法安全中断某些代码段时阻止它们。

    此类关键部分会不时调用中断点,并且如果在执行关键部分时收到信号,则会延迟其处理程序,直到发生下一个中断点或退出关键部分为止。

    您可以从源代码中的 quit.h 开始挖掘。

    因此,在我们的情况下,似乎bash有时在关键部分中会收到SIGHUPSIGHUP处理程序的执行被延迟,并且bash读取EOF并终止,然后退出关键部分或调用下一个中断点。

    引用

    官方Glibc手册中的
  • "Job Control"部分。
  • “Linux编程接口(interface)”一书的第34章“进程组, session 和作业控制”。
  • 09-26 07:02