Go程序当父进程被kill,子进程也自动退出的问题记录

2023-10-27

平常我们启动一个后台进程,会通过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

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go程序当父进程被kill,子进程也自动退出的问题记录 的相关文章

随机推荐

  • 编程的美学标准诌议

    编程的美学标准诌议 做了几年的程序员 虽然自己写的代码还远远没有达到要求 但在日复一日的实践过程中 我逐渐开始信奉一条标准 在实现功能的前提下 简单即是美 其实 编程的过程就好比是一个建模的过程 设计就是将一个现实问题抽象成逻辑模型 而编码
  • git命令使用上传下载详情大全...

    不罗嗦直接上内容 git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git branch a 查看所有的分支 git branch r 查看远程所有分支 git commit am in
  • CISCN(Web Ezpentest)GC、序列化、case when

    目录 REGEXP的一个点 正则 like 默认不区分大小写 当禁用了空格 regexp like的区分大小写的使用方法 CISCN 2022 初赛 ezpentest 卡点 2022 HFCTF babysql 最近又学到了一道新知识 c
  • attrs.xml中declare-styleable 详解(用于自定义控件的属性)

    1 框架定义
  • simulink电力电子仿真(3)单相桥式全控整流电路

    simulink电力电子仿真 3 单相桥式全控整流及有源逆变电路 返回目录 主要是赶上了疫情 然后期末要疯狂补实验报告 就索性写一下吧 万一以后再做电力电路仿真 可能会有用的 也希望可以帮助别人 器件的选择及位置 MATLAB的版本 201
  • 【k8s集群管理工具篇】云原生之部署K8s管理面板KubePi

    k8s集群管理工具篇 云原生之部署K8s管理面板KubePi 一 KubePi介绍 二 环境规划 三 检查本地环境 1 检查k8s集群状态 2 检查kubepi管理主机环境 三 部署KubePi 1 创建KubePi容器 2 检查KubeP
  • Flutter填坑 编译运行不起来

    记录下Flutter中遇到的一些问题 基本上按照Flutter中文网的教程可以完成Flutter环境的搭建 Flutter中文网 https flutterchina club Windows 环境 https flutterchina c
  • sqli-labs 靶场环境搭建

    目录 一 搭建环境所需资源 搭建sqli labs 靶场需要的运行环境 二 搭建过程 1 下载资源 2 创建网站 3 更改配置文件 4 安装数据库 不使用 php7 x 版本的原因 一 搭建环境所需资源 搭建sqli labs 靶场需要的运
  • 21计算机考研国家线,来了!21考研国家线公布!附详细解读!

    原标题 来了 21考研国家线公布 附详细解读 21考研人最近大概都在焦虑的等待国家线 昨天中国农业大学的一条消息直接将 考研国家线 顶上热搜 这不 最新出炉的国家线就来了 21考研国家线公布 21国家线学硕总分线上涨的门类有 经济学 历史学
  • 人工智能还是人工智障

    序言 有的时候感觉有脑子 有的时候感觉没有 到底是有还是没有呢 机器人 有的很智能 有的很智障 是智能的时候可爱 还是在智障的时候可爱 你是惧怕智障还是惧怕人工智能 风言风语 作为一个吵架之王 每次吵架的时候都会想 现在人工智能这么多 但是
  • 【支持向量机】最大间隔超平面及Matlab代码

    线性可分 在特征空间中 有两个训练样本可以通过一条直线区分开 则称为线性可分 而在特征空间大于等于四维时 分开训练样本的平面 称为超平面 我们定义一条直线方程 1 x 1
  • Linux 之exit() 进程退出函数

    进程的退出 linux下进程数量太多会导致系统崩溃 在使用完一个进程之后要及时终止它 进程退出一般有三种方法 1 在main函数中使用 return关键字 使用 return 后系统会调用 exit 函数来终止进程 2 手动调用 exit
  • C++ 关于 protobuf的一些操作

    先是定义部分 下面跟一些例子组成 message DBRoleData uint64 RoleID 2 string Name 6 repeated int64 Action 12 存内置重复单位 message DBRoleLoginAc
  • Kylin 10 SP1(UI)磁盘自行配置lvm

    1 登录服务器 输入 lsblk 查看新磁盘名称 我以sdb为例 sdb1是我为其建立的分区 2 新建分区 fidsk dev sdb 先输入n 新建分区 然后输入p 建立分区 其余选项默认 最后一步输入w保存 3 格式化分区 mkfs x
  • strapi的使用(二)-- Graphql

    一 Graphql 一种为你的API而生的查询语言 可以理解为动态api 一般来说我们都是在后端写好sql查询语句查询数据库数据 前端请求这个api返回的数据是固定的 而Graphql可以让前端去决定请求什么字段回来 二 strapi安装G
  • OPENSSL库的使用-RSA篇

    一 RSA算法简介 RSA公钥加密算法是1977年由Ron Rivest Adi Shamirh和LenAdleman在 美国麻省理工学院 开发的 RSA取名来自开发他们三者的名字 RSA是目前最有影响力的公钥加密算法 它能够抵抗到目前为止
  • 我的GIT练习TWO

    目录 前言 GIT安装教程 Git作者 GIT优点 GIT缺点 为什么要使用 Git GIT练习TWO C1 C2 C3 C4 C5 C6 C7 总结 前言 Git 是一个分布式版本控制及源代码管理工具 Git 可以为你的项目保存若干快照
  • vue3+element-plus上传文件,预览文件

    vue3 ts element plus上传文件 预览文件 场景 使用element plus的el upload标签 手动上传文件 可预览docx xlsx pdf jpg jpeg png 本地资源以及网络资源 1 使用el uploa
  • 三废的日常--Nginx实现负载均衡

    第二天 小废给大废买了杯奶茶 大废 这才差不多 讲了这么多早就应该给我奶茶了 吧唧吧唧 大废 那今天就来讲讲Nginx是如何实现负载均衡吧 二废 这个我知道 我看过Nginx的配置 nginx通过upstream下的配置 对配置的服务器进行
  • Go程序当父进程被kill,子进程也自动退出的问题记录

    平常我们启动一个后台进程 会通过nouhp 的方式启动 这样可以在退出终端会话的时候 进程仍然可以继续在后台执行 进程的父进程id会从原来的bash进程变成1 在go程序中 通过nouhp 的方式启动子进程 预期是即使父进程挂掉 子进程也能