原因就是在shell退出时,会给在该shell内开启的进程发送SIGHUP,如果指定程序没有处理这个signal,就会执行默认行为,也就是退出。 00 sleep 100 ➜ ~ kill 23597 ➜ ~ ps -ef | grep sleep 我们可以看到,即使shell退出了,sleep也没有退出,因为nohup使sleep进程忽略了SIGHUP 在bash中测试时,关闭bash并没有给sleep进程发送SIGHUP。 更多signal的信息请看Linux下的signal机制
SIGHUP信号 在介绍SIGHUP信号之前,先来了解两个概念:进程组和会话。 SIGHUP信号的触发及默认处理 在对会话的概念有所了解之后,我们现在开始正式介绍一下SIGHUP信号,SIGHUP 信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 系统对SIGHUP信号的默认处理是终止收到该信号的进程。所以若程序中没有捕捉该信号,当收到该信号时,进程就会退出。 当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。 当xinetd程序在接收到SIGHUP信号之后调用hard_reconfig函数,它将循环读取/etc/xinetd.d/目录下的每个子配置文件,并检测其变化。
在bash的man中,看到了这样的解释 The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. 也就是说interactive shell只会将SIGHUP信号给子任务 如果父shell需要将SIGTERM信号传播给子任务,常用的一个方法是用exec运行子任务 更详细的文章可以参考http://
这里为避免歧义,特此解释: "kill -hup" 是一个用于发送 SIGHUP 信号给进程的命令。 SIGHUP 信号是一种发送给进程的 POSIX 信号,代表终端挂起信号(hangup signal)。 , reloading configuration files"))); ProcessConfigFile(PGC_SIGHUP); SignalChildren(SIGHUP); if = 0) signal_child(StartupPID, SIGHUP); if (BgWriterPID ! = 0) signal_child(AutoVacPID, SIGHUP); if (PgArchPID !
为什么 该现象与SIGHUP信号有关 在POSIX-compliant平台(Solaris,MacOS 等)[1]上,当终端logout时,该终端下所有进程会收到SIGHUP信号 在Android, FreeBSD Linux Distributions等平台(遵循大部分POSIX标准, 但是没有认证),当 bash 设置huponexit为on时(可通过shopt命令设置),终端logout会给该终端所有进程发送SIGHUP 信号 注:注意当通过直接关闭终端窗口,而非通过logout,exit等命令退出当前终端时,不论shopt设置,终端都会给其下所有进程发送SIGHUP信号。 实现方式 实现进程免受终端SIGHUP信号影响的原理主要有两种: 使进程屏蔽SIGHUP信号,如nohup 使进程脱离当前终端,这样当前终端的SIGHUP信号自然不会引起进程中断,如disown,setsid 当前台已经执行任务时,使用Ctrl z将当前进程挂起到后台暂停运行,使用bg %1命令使后台挂起命令继续运行,再使用disown -h %1使进程忽略SIGHUP信号。
STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSED # kill -l 1) SIGHUP install.log 用户 进程号 权限 命令 /root/install.log: root 3347 f.... tail fuser -k -SIGHUP
SIGHUP [ 0 11681 sshd: hongjiang.wanghj [priv] ] -> [ 57316 11700 bash ] SIGHUP [ 57316 11700 -bash ] -> [ 57316 11700 bash ] SIGHUP [ 57316 11700 ] -> [ 0 13299 tail ] SIGHUP [ 57316 11700 ] -> [ 0 13298 2) 为什么SIGHUP (kill -1) 会让tomcat进程退出? SIGHUP (kill -1) 让tomcat进程退出的原因 在非交互模式下,shell对java进程设置了SIGINT,SIGQUIT信号设置了忽略,但并没有对SIGHUP信号设为忽略。 传递给bash进程后,bash会把SIGHUP传递给它的子进程,并且对于其子进程test.sh,bash还会对test.sh的进程组里的成员都传播一遍SIGHUP。
这个问题就先暂且留作思考题吧~ 4、SIGHUP 信号的意义与作用 刚有同学问我 SIGHUP 和 kill -9 的区别,后者属于强杀进程,可能内存中的进程数据还没持久化就结束进程,带来的危害是数据丢失 下面具体聊聊 SIGHUP 的问题。 SIGHUP的含义是连接断开,系统对SIGHUP信号的默认处理是终止收到该信号的进程。 4、kill -1,-1 对应的 signal 是 SIGHUP,SIGHUP对daemon是重新读取配置,对普通进程就是杀掉。 一般的守护进程都会在收到这个信号时重新加载配置(本质上由开发者决定),因为 SIGHUP 本来的意义对守信进程没有意义(SIGHUP 是当控制终端失去连接时触发的信号,而守护进程没有控制终端,所以根本用不上
用户准备退出 session系统向该 session 发出SIGHUP信号session 将SIGHUP信号发给所有子进程子进程收到SIGHUP信号后,自动退出 上面的流程解释了,为什么"前台任务"会随着 session 的退出而退出:因为它收到了SIGHUP信号。 那么,"后台任务"是否也会收到SIGHUP信号? 这由 Shell 的huponexit参数决定的。 因此,session 退出的时候,不会把SIGHUP信号发给"后台任务"。所以,一般来说,"后台任务"不会随着 session 一起退出。 一个"后台任务"只要不在这个列表之中,session 就肯定不会向它发出SIGHUP信号。
这种情况下,如果用户直接关闭ssh终端的窗口,sshd会把SIGHUP信号传递给bash进程,bash会把SIGHUP传递给seeyonupdate进程及该进程所属的进程组的所有进程成员。 (java后台进程继承了父进程startup.sh的pgid,所以java进程仍属于进程组里的成员,收到SIGHUP后会退出。 ;脚本的最后,通过执行tail命令,对日志信息进行查看(此时,seeyonupdate脚本并未退出,而是挂在了tail进程上) 2)用户关闭了ssh终端窗口或网络断开导致ssh连接断开,sshd会把SIGHUP 信号发给了窗口内的bash进程,bash进程会把SIGHUP传递给seeyonupdate进程及该进程所属的进程组的所有进程成员。 (java后台进程继承了父进程startup.sh的pgid,所以java进程仍属于进程组里的成员,也会收到SIGHUP信号) Tomcat收到SIGHUP信号后,会激活SIGHUP handler线程
此时如果关掉session,程序会收到一个 SIGHUP信号,程序会不会关闭呢? 信号量 SIGHUP 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业,这时它们与控制终端不再关联。 当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。 关闭session,发送SIGHUP信号,再来看看。 使用Ctrl + C发送SIGINT信号,程序关闭 关闭session发送SIGHUP信号,程序免疫 平日线上经常使用 nohup和 &配合来启动程序 同时免疫SIGINT和SIGHUP信号 (
此时如果关掉session,程序会收到一个SIGHUP信号,此时会怎么样呢? ps再次确认,可以看到关闭session之后,进程号是32389的a.out进程也关闭了。 使用nohup . 此时如果关掉session,程序会收到一个SIGHUP信号,程序会不会关闭呢? 关掉session后,再次ps看一下,ID为32437的a.out进程还在。 关闭session,发送SIGHUP信号,再来看看。 ID为32524的进程依然存在,后续也只能用kill来关闭它。 结论 使用&后台运行程序: 结果会输出到终端 使用Ctrl + C发送SIGINT信号,程序免疫 关闭session发送SIGHUP信号,程序关闭 使用nohup运行程序: 结果默认会输出到nohup.out 使用Ctrl + C发送SIGINT信号,程序关闭 关闭session发送SIGHUP信号,程序免疫 平日线上经常使用nohup和&配合来启动程序: 同时免疫SIGINT和SIGHUP信号 同时,还有一个最佳实践
此时如果关掉session,程序会收到一个SIGHUP信号,此时会怎么样呢? ? ps再次确认,可以看到关闭session之后,进程号是32389的a.out进程也关闭了。 使用nohup . 此时如果关掉session,程序会收到一个SIGHUP信号,程序会不会关闭呢? ? 关掉session后,再次ps看一下,ID为32437的a.out进程还在。 ? 关闭session,发送SIGHUP信号,再来看看。 ? ID为32524的进程依然存在,后续也只能用kill来关闭它。 结论 使用&后台运行程序: 结果会输出到终端 使用Ctrl + C发送SIGINT信号,程序免疫 关闭session发送SIGHUP信号,程序关闭 使用nohup运行程序: 结果默认会输出到nohup.out 使用Ctrl + C发送SIGINT信号,程序关闭 关闭session发送SIGHUP信号,程序免疫 平日线上经常使用nohup和&配合来启动程序: 同时免疫SIGINT和SIGHUP信号 同时,还有一个最佳实践
在了解如何解决问题前,我觉得有必要了解下为什么前台任务会随着 session 的退出而退出(收到了 SIGHUP)。 Linux 系统对此的设计如下: 1、用户准备退出 session 2、系统向该 session 发出SIGHUP信号 3、session 将SIGHUP信号发给所有子进程 4、子进程收到SIGHUP信号后 ,自动退出 SIGHUP 是什么 SIGHUP(signal hang up) 信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一 session 内的各个作业, 系统对 SIGHUP 信号的默认处理是终止收到该信号的进程。 我们知道进程收到 SIGHUP 信号会被终止,那么后台进程是否会收到 SIGHUP 信号挂掉?掏出阿里云服务器实验下。 这。。。后台进程在我们退出 session 后挂掉了!!!,这是为啥?
信号处理使用channel通信 func catchSignal() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP for { s := <-c logger.Info("收到信号 -- ", s) switch s { case syscall.SIGHUP fmt.Println(str) } } func catchSignal() { d := make(chan os.Signal, 1) signal.Notify(d, syscall.SIGHUP for { s := <-d fmt.Println("收到信号 -- ", s) switch s { case syscall.SIGHUP
SIGHUP [ 0 11681 sshd: hongjiang.wanghj [priv] ] -> [ 57316 11700 bash ] SIGHUP [ 57316 11700 -bash ] -> [ 57316 11700 bash ] SIGHUP [ 57316 11700 ] -> [ 0 13299 tail ] SIGHUP [ 57316 11700 ] -> [ 0 13298 2) 为什么SIGHUP (kill -1) 会让tomcat进程退出? SIGHUP (kill -1) 让tomcat进程退出的原因 在非交互模式下,shell对java进程设置了SIGINT,SIGQUIT信号设置了忽略,但并没有对SIGHUP信号设为忽略。 传递给bash进程后,bash会把SIGHUP传递给它的子进程,并且对于其子进程test.sh,bash还会对test.sh的进程组里的成员都传播一遍SIGHUP。
),那什么情况下会触发linux下SIGHUP信号呢,以下内容摘自百度百科: SIGHUP会在以下3种情况下被发送给相应的进程: 1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程 结合 1和2 我们知道,不管是否以 & (job方式)启动的进程,关闭终端时都会收到 SIGHUP 信号 ,那么进程收到 SIGHUP 信号会如何处理呢,看同样是摘自百度百科的一句话 系统对SIGHUP 也就是说关闭终端进程会收到SIGHUP信号,而该信号的默认处理方/【当下浏览的服务器和开发工具是哪些】/式就是结束掉该进程,当然 我们也可以自己处理该信号,或者忽略它,同样是上述循环的例子,我们稍加改进 php declare(ticks = 1); pcntl_signal(SIGHUP, function(){ // 这地方处理信号的方式我们只是简单的写入一句日志到文件中 file_put_contents ('logs.txt', 'pid : ' . posix_getpid() . ' receive SIGHUP 信号' .
synchronous_standby_names为空,即改为异步,然后持久化到postgresql.auto.conf中,最好通过pg_reload_conf函数(通知所有进程更新配置)向Postmaster(主进程)进程发送SIGHUP 信号 4)主进程处理SIGHUP信号的函数为SIGHUP_handler,该函数会向所有子进程包括后台进程发送SIGHUP信号。 这里关注checkpoint进程 5)checkpoint进程接收到SIGHUP信号后,ChkptSigHupHandler将got_SIGHUP变量置为true,然后checkpoint进程轮一圈后, 注意:主进程SIGHUP_handler会向所有子进程发送SIGHUP信号,也就是事务等待进程也会接收到SIGHUP信号,它处理SIGHUP信号的函数是PostgresSigHupHandler,会SetLatch 当然,这还得checkpoint进程来唤醒让同步复制不在等待而赶紧走掉: PostgresMain pqsignal(SIGHUP, PostgresSigHupHandler); |-- {
用户准备退出 session 系统向该 session 发出SIGHUP信号 session 将SIGHUP信号发给所有子进程 子进程收到SIGHUP信号后,自动退出 上面的流程解释了,为什么”前台任务 ”会随着 session 的退出而退出:因为它收到了SIGHUP信号。 那么,”后台任务”是否也会收到SIGHUP信号? 这由 Shell 的huponexit参数决定的。 因此,session 退出的时候,不会把SIGHUP信号发给”后台任务”。所以,一般来说,”后台任务”不会随着 session 一起退出。 一个”后台任务”只要不在这个列表之中,session 就肯定不会向它发出SIGHUP信号。
经过测试,有发现: a) 用 ctrl-c 终止当前test.sh进程时,系统events进程向 java 和 tail 两个进程发送了SIGINT 信号 b) 关闭ssh终端窗口时,sshd向下游进程发送SIGHUP 在非交互模式下,shell对java进程设置了SIGINT,SIGQUIT信号设置了忽略,但并没有对SIGHUP信号设为忽略,回头看上面说的,直接关闭ssh终端窗口时,sshd向下游进程发送SIGHUP 再看一下当时的进程层级: |-sshd(1622)-+-sshd(11681)—sshd(11699)—bash(11700)—test.sh(13285)—tail(13299) sshd把SIGHUP 传递给bash进程后,bash会把SIGHUP传递给它的子进程,并且对于其子进程test.sh,bash还会对test.sh的进程组里的成员都传播一遍SIGHUP。 因为java后台进程从父进程catalina.sh(又是从其父进程test.sh)继承的pgid,所以java进程仍属于test.sh进程组里的成员,收到SIGHUP后退出。