如果我们closures已经启动的terminal,linux是否会终止后台进程?

我有一个embedded式系统,我做了telnet ,然后在后台运行一个应用程序:

 ./app_name & 

现在,如果我closures我的terminal,并从其他terminal做telnet ,如果我检查,然后我可以看到这个过程仍在运行。

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

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

我在后台运行这个程序在我的本地Linux电脑上,我closures了terminal。

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

我的问题是:

  • 为什么对同一types的过程的未定义的行为?
  • 它依赖于哪个?
  • 它依赖于Linux的版本吗?

Solutions Collecting From Web of "如果我们closures已经启动的terminal,linux是否会终止后台进程?"

谁应该杀死工作?

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


内核什么时候发送SIGHUP

内核发送SIGHUP控制进程

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

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

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

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

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

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

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


什么时候bash发送SIGHUP

BashSIGHUP发送到所有作业(前景和背景):

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

在这里看到更多细节。

笔记:

  • bash 发送SIGHUP到使用disown从工作列表中删除的工作;
  • 使用nohup开始的进程忽略 SIGHUP

更多细节在这里 。


那么其他的shell呢?

通常情况下,shell会传播SIGHUP 。 在正常退出时生成SIGHUP不太常见。


Telnet或SSH

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

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

问题

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

当服务器( telnetddropbear )关闭pty的主端时,似乎会出现竞争状态

  1. 通常情况下, bash收到SIGHUP并立即杀死后台作业(如预期)并终止;
  2. 但有时, 处理SIGHUP 之前bash会在pty的slave侧检测EOF

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


可以配置bash在普通的出口(包括EOF )上发送SIGHUP

  • 确保bash作为登录shell启动。 huponexit仅适用于登录shell,AFAIK。

    登录shell是通过-l选项或argv[0] 前导连字符来启用的。 您可以将telnetd配置为运行/bin/bash -l或更好的/bin/login ,以login shell模式调用/bin/sh

    例如:

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

    例如:

     shopt -s huponexit
    

    每次在bash会话中输入它,或将其添加到.bashrc/etc/profile


为什么比赛会发生?

只有在安全的情况下, bash才能解除阻塞信号,并且当信号处理程序不能安全地中断某些代码段时阻止它们。

这样的关键部分不时地调用中断点 ,并且如果在关键部分被执行时接收到信号,则处理器被延迟直到下一个中​​断点发生或关键部分退出。

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

因此,在我们的例子中, bash有时会在关键部分收到SIGHUPSIGHUP处理程序执行被延迟, bash读取EOF退出临界区或调用下一个中断点之前终止。


参考

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

AFAIK在这两种情况下的过程应该被杀害。 为了避免这种情况,你必须发出如下的nohup:

 > nohup ./my_app & 

这样你的过程将继续执行。 远程登录部分可能是由于类似于这个BUG:

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

为了完全理解发生了什么,你需要进入unix内部。

当你正在运行这样的命令

./app_name &

app_name被发送到后台进程组。 你可以在这里查看关于unix进程组的信息

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

为了让您的应用程序在退出bash时运行,您需要使用nohup实用程序使您的应用程序免于挂断信号。

nohup – 运行一个免于hangups的命令,输出到非tty

最后,这是你如何做到这一点。

nohup app_name & 2> /dev/null;

当你关闭终端时,shell将SIGHUP发送给所有的后台进程 – 并且杀死它们。 这可以通过几种方式来抑制,最显着的是:

nohup的

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

 $ nohup app & 

disown告诉shell不要发送SIGHUP

 $ app & $ disown 

它依赖于Linux的版本?

这取决于你的shell。 以上至少适用于bash