如果我们关闭启动它的终端,Linux会杀死后台进程吗? [英] Does linux kill background processes if we close the terminal from which it has started?
问题描述
我有一个嵌入式系统,在该系统上执行telnet
,然后在后台运行一个应用程序:
I have an embedded system, on which I do telnet
and then I run an application in background:
./app_name &
现在,如果我关闭终端并在其他终端上执行telnet
,如果我检查了一下,便可以看到此过程仍在运行.
Now if I close my terminal and do telnet
from other terminal and if I check then I can see this process is still running.
要对此进行检查,我编写了一个小程序:
To check this I have written a small program:
#include<stdio.h>
main()
{
while(1);
}
我在后台的本地linux PC中运行了该程序,然后关闭了终端.
I ran this program in my local linux pc in background and I closed the terminal.
现在,当我从其他终端检查此过程时,我发现该过程也被杀死了.
Now, when I checked for this process from other terminal then I found that this process was also killed.
我的问题是:
- 为什么相同类型的过程具有未定义的行为?
- 它依赖于什么?
- 它取决于Linux版本吗?
推荐答案
谁应该杀死工作?
通常,前台和后台作业会在不同情况下被内核或外壳程序发送的SIGHUP
杀死.
内核将SIGHUP
发送到 控制过程 :
Kernel sends SIGHUP
to controlling process:
- 对于真实(硬件)终端:在终端驱动程序中检测到断开连接时,例如在调制解调器线路挂断时;
- 用于伪终端(pty):当关闭引用pty主节点的最后一个描述符时,例如当您关闭终端窗口时.
- for real (hardware) terminal: when disconnect is detected in a terminal driver, e.g. on hang-up on modem line;
- for pseudoterminal (pty): when last descriptor referencing master side of pty is closed, e.g. when you close terminal window.
内核将SIGHUP
发送到其他进程组:
Kernel sends SIGHUP
to other process groups:
- 控制进程终止时,
- 进入前景进程组;
- 到 孤立的进程组 ,当它成为孤立的并且已停止成员时.
- to foreground process group, when controlling process terminates;
- to orphaned process group, when it becomes orphaned and it has stopped members.
控制过程是建立与控制终端的连接的会话负责人.
Controlling process is the session leader that established the connection to the controlling terminal.
通常,控制过程是您的外壳.因此,总结一下:
Typically, the controlling process is your shell. So, to sum up:
-
当真正或伪终端断开/关闭时,
- 内核将
SIGHUP
发送到外壳;
当外壳终止时, - 内核将
SIGHUP
发送到前台进程组; - 内核将
SIGHUP
发送到孤立的进程组(如果它包含已停止的进程).
- kernel sends
SIGHUP
to the shell when real or pseudoterminal is disconnected/closed; - kernel sends
SIGHUP
to foreground process group when the shell terminates; - kernel sends
SIGHUP
to orphaned process group if it contains stopped processes.
请注意,如果内核不包含停止的进程,则不会将SIGHUP
发送到后台进程组.
Note that kernel does not send SIGHUP
to background process group if it contains no stopped processes.
Bash 将SIGHUP
发送到所有作业(前景和背景):
Bash sends SIGHUP
to all jobs (foreground and background):
- 当它收到
SIGHUP
并且是交互式外壳程序时(并且在编译时启用了 job control 支持); - 退出时,它是一个交互式登录外壳,并设置了
huponexit
选项(并且在编译时启用了 job control 支持).
- when it receives
SIGHUP
, and it is an interactive shell (and job control support is enabled at compile-time); - when it exits, it is an interactive login shell, and
huponexit
option is set (and job control support is enabled at compile-time).
在此处查看更多详细信息.
注意:
-
bash
不将SIGHUP
发送到使用disown
从作业列表中删除的作业; - 使用
nohup
ignoreSIGHUP
开始的进程.
bash
does not sendSIGHUP
to jobs removed from job list usingdisown
;- processes started using
nohup
ignoreSIGHUP
.
更多详细信息此处.
通常,shell传播SIGHUP
.在普通出口生成SIGHUP
的情况较少.
Usually, shells propagate SIGHUP
. Generating SIGHUP
at normal exit is less common.
在telnet或SSH下,关闭连接时(例如,在PC上关闭telnet
窗口时),应该发生以下情况:
Under telnet or SSH, the following should happen when connection is closed (e.g. when you close telnet
window on PC):
- 客户端被杀死;
- 服务器检测到客户端连接已关闭;
- 服务器关闭pty的主服务器端;
- 内核检测到主pty已关闭,并将
SIGHUP
发送给bash
; -
bash
接收SIGHUP
,将SIGHUP
发送给所有作业并终止; - 每个作业接收
SIGHUP
并终止.
- client is killed;
- server detects that client connection is closed;
- server closes master side of pty;
- kernel detects that master pty is closed and sends
SIGHUP
tobash
; bash
receivesSIGHUP
, sendsSIGHUP
to all jobs and terminates;- each job receives
SIGHUP
and terminates.
问题
我可以使用bash
和telnetd
从busybox
或dropbear
SSH服务器重现您的问题:有时,后台作业不会收到SIGHUP
(并且不会终止)关闭客户端连接.
Problem
I can reproduce your issue using bash
and telnetd
from busybox
or dropbear
SSH server: sometimes, background job doesn't receive SIGHUP
(and doesn't terminate) when client connection is closed.
当服务器(telnetd
或dropbear
)关闭pty的主服务器端时,似乎出现了竞赛条件:
It seems that a race condition occurs when server (telnetd
or dropbear
) closes master side of pty:
- 通常,
bash
接收到SIGHUP
并立即终止后台作业(如预期的那样)并终止; - 但有时,
bash
在处理SIGHUP
之前在pty 的从属端检测到EOF
.
- normally,
bash
receivesSIGHUP
and immediately kills background jobs (as expected) and terminates; - but sometimes,
bash
detectsEOF
on slave side of pty before handlingSIGHUP
.
当bash
检测到EOF
时,默认情况下它将立即终止而不发送SIGHUP
.后台作业仍在运行!
When bash
detects EOF
, it by default terminates immediately without sending SIGHUP
. And background job remains running!
也可以将bash
配置为在正常出口(包括EOF
)上发送SIGHUP
:
It is possible to configure bash
to send SIGHUP
on normal exit (including EOF
) too:
-
确保
bash
作为登录外壳启动.huponexit
有效仅适用于登录Shell AFAIK.
Ensure that
bash
is started as login shell. Thehuponexit
works only for login shells, AFAIK.
Login shell is enabled by -l
option or leading hyphen in argv[0]
. You can configure telnetd
to run /bin/bash -l
or better /bin/login
which invokes /bin/sh
in login shell mode.
例如:
telnetd -l /bin/login
启用huponexit
选项.
例如:
shopt -s huponexit
每次在bash
会话中键入此内容,或将其添加到.bashrc
或/etc/profile
.
Type this in bash
session every time or add it to .bashrc
or /etc/profile
.
bash
仅在安全的情况下取消阻止信号,并在信号处理程序无法安全中断某些代码段的情况下阻止它们.
bash
unblocks signals only when it's safe, and blocks them when some code section can't be safely interrupted by a signal handler.
此类关键部分会不时调用中断点,如果在执行关键部分时收到信号,则其处理程序将延迟到下一个中断点发生或关键部分已退出.
Such critical sections invoke interruption points from time to time, and if signal is received when a critical section is executed, it's handler is delayed until next interruption point happens or critical section is exited.
您可以从 quit.h
开始挖掘在源代码中.
You can start digging from quit.h
in the source code.
因此,在我们的案例中,bash
有时在关键部分中有时会收到SIGHUP
. SIGHUP
处理程序执行被延迟,并且bash
读取EOF
并在退出关键部分或调用下一个中断点之前终止.
Thus, it seems that in our case bash
sometimes receives SIGHUP
when it's in a critical section. SIGHUP
handler execution is delayed, and bash
reads EOF
and terminates before exiting critical section or calling next interruption point.
-
官方Glibc中的
- 作业控制" 部分手册.
- "Linux编程接口"一书的第34章进程组,会话和作业控制".
- "Job Control" section in official Glibc manual.
- Chapter 34 "Process Groups, Sessions, and Job Control" of "The Linux Programming Interface" book.
这篇关于如果我们关闭启动它的终端,Linux会杀死后台进程吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!