如果我们关闭它已经启动的终端,linux会杀死后台进程吗?

Chi*_*rag 20 linux shell telnet job-control

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

./app_name &
Run Code Online (Sandbox Code Playgroud)

现在如果我关闭我的终端并telnet从其他终端做,如果我检查然后我可以看到这个过程仍在运行.

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

#include<stdio.h>
main()
{
    while(1);
}
Run Code Online (Sandbox Code Playgroud)

我在后台运行我的本地linux pc程序,然后我关闭了终端.

现在,当我从其他终端检查这个过程时,我发现这个过程也被杀死了.

我的问题是:

  • 为什么相同类型的进程的未定义行为?
  • 它依赖于哪个?
  • 它是否依赖于Linux的版本?

gav*_*avv 35

谁应该杀死工作?

通常,前台和后台作业SIGHUP在不同情况下由内核或shell发送.


内核何时发送SIGHUP

内核发送SIGHUP控制进程:

  • 用于实际(硬件)终端:当在终端驱动器中检测到断开时,例如在调制解调器线路上挂断;
  • for pseudoterminal(pty):当引用pty主端的最后一个描述符关闭时,例如当你关闭终端窗口时.

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

  • 前台进程组,当控制进程终止时;
  • 孤立进程组,当它成为孤儿,而且它已经停止成员.

控制过程是建立与控制终端的连接的会话负责人.

通常,控制过程就是你的shell.所以,总结一下:

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

请注意,如果内核SIGHUP包含已停止的进程,则它不会发送到后台进程组.


什么时候bash发送SIGHUP

Bash发送SIGHUP所有作业(前台和后台):

  • 当它收到时SIGHUP,它是一个交互式shell(并且在编译时启用了作业控制支持);
  • 当它退出时,它是一个交互式登录shell,并且huponexit设置了选项(并且在编译时启用了作业控制支持).

在这里查看更多细节.

笔记:

  • bash 不会发送SIGHUP到工作清单中删除的工作disown;
  • 进程开始使用nohup ignore SIGHUP.

更多细节在这里.


其他贝壳怎么样?

通常,shell会传播SIGHUP.SIGHUP在正常出口处生成不太常见.


Telnet或SSH

在telnet或SSH下,连接关闭时会发生以下情况(例如,当您关闭telnetPC上的窗口时):

  1. 客户被杀;
  2. 服务器检测到客户端连接已关闭;
  3. 服务器关闭pty的主端;
  4. 内核检测到主PTY被关闭,并发送SIGHUPbash;
  5. bash接收SIGHUP,发送SIGHUP到所有工作并终止;
  6. 每个工作都会收到SIGHUP并终止.

问题

我可以重现使用您的问题bash,并telnetdbusyboxdropbearSSH服务器:有时,后台作业不接收SIGHUP(并且不终止),当客户端连接关闭.

当服务器(或)关闭pty的主端时,似乎发生了竞争条件:telnetddropbear

  1. 通常,bash接收SIGHUP并立即杀死后台工作(如预期的那样)并终止;
  2. 但有时,处理bash检测EOFpty的奴隶侧.SIGHUP

bash检测EOF,默认情况下它会立即终止,不发送SIGHUP.后台工作仍在运行!


也可以配置bashSIGHUP正常退出(包括EOF):

  • 确保bash登录shell启动.该huponexit 作品只为登录shell,据我所知.

    登录壳是由启用-l选项,或导致连字符argv[0].您可以配置telnetd为在登录shell模式下运行/bin/bash -l或更好地/bin/login调用/bin/sh.

    例如:

    telnetd -l /bin/login
    
  • 启用huponexit选项.

    例如:

    shopt -s huponexit
    

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


比赛为什么会发生?

bash 仅在信号安全时解锁信号,并在信号处理程序无法安全中断某些代码段时阻止它们.

这些关键部分不时地调用中断点,并且如果在执行关键部分时接收到信号,则它的处理程序被延迟直到下一个中​​断点发生或退出临界区.

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

因此,在我们的情况下,似乎bash有时会SIGHUP在关键部分接收.SIGHUP处理程序执行被延迟,并退出临界区或调用下一个中断点之前bash读取EOF和终止.


参考

  • 官方Glibc手册中的"工作控制"部分.
  • 第34章"Linux编程接口"一书中的"进程组,会话和作业控制".


rka*_*ach 5

AFAIK 在这两种情况下都应该终止进程。为了避免这种情况,您必须发出如下所示的 nohup:

> nohup ./my_app &
Run Code Online (Sandbox Code Playgroud)

这样您的流程将继续执行。可能telnet部分是由于一个类似于这个的BUG:

https://bugzilla.redhat.com/show_bug.cgi?id=89653


dei*_*mus 5

为了完全了解正在发生的事情,您需要unix稍微了解一下内部结构。

当你运行这样的命令时

./app_name &

app_name被发送到后台进程组。您可以在此处查看unix进程组

当您bash以正常退出关闭时,它会触发SIGHUP所有作业的挂断信号。有关unix作业控制的一些信息在这里

为了在您退出时保持您的应用程序运行,您bash需要使您的应用程序免受nohup实用程序挂断信号的影响。

nohup - 运行一个不受挂断影响的命令,输出到非 tty

最后这就是你需要做的事情。

nohup app_name & 2> /dev/null;


pac*_*lik 5

当你关闭终端时,shell会发送SIGHUP到所有后台进程 - 并且会杀死它们.这可以通过多种方式得到抑制,最值得注意的是:

nohup的

当你运行程序时,nohup它会捕获SIGHUP并重定向程序输出.

$ nohup app &
Run Code Online (Sandbox Code Playgroud)

disown 告诉shell不发送 SIGHUP

$ app &
$ disown
Run Code Online (Sandbox Code Playgroud)

它依赖于linux的版本吗?

它取决于你的shell.以上至少适用于bash.