平常我们启动一个后台进程,会通过nouhp &的方式启动,这样可以在退出终端会话的时候,进程仍然可以继续在后台执行(进程的父进程id会从原来的bash进程变成1)
在go程序中,通过nouhp &的方式启动子进程,预期是即使父进程挂掉,子进程也能继续执行
但是测试过程中发现,当父进程被kill,子进程也会自动退出
首先需要了解下什么是SIGHUP和SIGTERM
1.SIGHUP(Hangup)信号通常是由终端或控制台断开时产生的信号
它的作用是通知进程重新读取其配置文件,或者让进程重新初始化,以便于适应新的环境。
在进程收到该信号时,一般会在日志中记录相关信息,然后进行优雅的退出或重新初始化。
2.SIGTERM(Terminate)信号是进程终止信号
它通常是由kill命令发送给进程的。它的作用是请求进程正常地退出,
进程在接收到该信号后,可以在清理后退出。
如果进程没有处理SIGTERM信号,则可以使用kill -9命令强制杀死进程。
正常情况下,一个程序如果没有进行特别处理,那么收到SIGHUP、SIGTERM信号都会退出
通常我们在一个终端会话中启动一个进程,如果只是通过&后台启动,那么当会话关闭的时候,进程也会自动退出
这是因为会话关闭的时候,会向子进程发送SIGHUP信号,导致子进程也跟着退出
而nohup的作用就是忽略NOHUP信号,避免进程退出
go程序中可以用signal.Notify监听SIGHUP信号修改默认行为,示例代码:
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
// 创建一个channel用于接收信号
signals := make(chan os.Signal, 1)
// 注册信号
signal.Notify(signals, syscall.SIGTERM, syscall.SIGHUP)
// 在goroutine中等待信号
go func() {
for {
select {
case sig := <-signals:
switch sig {
case syscall.SIGTERM:
fmt.Println("Received SIGTERM, shutting down gracefully...")
// 做一些清理工作
os.Exit(0)
case syscall.SIGHUP:
fmt.Println("Received SIGHUP, reloading configuration...")
// 重新加载配置
}
}
}
}()
// 主进程继续执行其他任务
fmt.Println("Server started...")
select {}
}
通过在子进程中用signal.Notify监听SIGHUP、SIGTERM信号,并打印日志,来进行测试(kill -1发送SIGHUP信号,kill发送SIGTERM信号)
查看日志发现,父进程被kill,子进程会收到SIGTERM信号
而nohup只是忽略SIGHUP信号,所以使用nohup启动自然就不能防止子进程退出了
解决方案是启动子进程时,修改子进程进程组id,这样子进程就不会收到SIGTERM信号了
Go示例代码:
package main
import (
"fmt"
"os/exec"
"strings"
"syscall"
)
func main() {
//这里child是上面子进程编译成的二进制程序
cmd := exec.Command("/bin/bash", "-c", "./child")
//SysProcAttr 字段被设置为 Setpgid 为 true,这将使子进程的进程组 ID 与其父进程不同。Pdeathsig 被设置为空信号,这意味着子进程在父进程退出时不会收到任何信号
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Pdeathsig: syscall.Signal(0),
}
output, err := cmd.CombinedOutput()
rs := strings.TrimSpace(string(output))
if err != nil {
fmt.Println("Command execution failed:", err, "rs:", rs)
os.Exit(1)
}
fmt.Println("rs:", rs)
}
ps -eo pid,ppid,pgrp,session,comm
可以通过这个命令来查看进程进程组id
还有一种情况要注意,即使不用Setpgid,使用kill -9的方式杀父进程,子进程也是不会退出的
针对一些希望父进程结束的时候,子进程也被跟着退出的场景,要么谨慎使用kill -9,要么自己做好进程退出的机制处理
参考资料:
https://blog.csdn.net/qq_34021712/article/details/115587702
https://cloud.tencent.com/developer/article/1497217
https://www.jianshu.com/p/e147d856074c%20