linux - 为什么即使使用 nohup 也能捕获挂断信号?

标签 linux go signals

package main

import (
    "os"
    "os/signal"

    log "github.com/sirupsen/logrus"
    "golang.org/x/sys/unix"
)

func main() {
    sigs := make(chan os.Signal, 1)
    signal.Notify(sigs, unix.SIGHUP)

    go func() {
        s := <-sigs
        log.Info("OS signal: " + s.String())
    }()

    DoSomething()
}

我编译了上面的 Go 代码并使用以下命令执行:

nohup ./build_linux > /dev/null 2>&1 &

但是当我退出终端时,该进程仍然捕获 HANGUP 信号。

看起来signal.Notify优先级更高,而nohup命令没有效果。

发生了什么以及为什么 nohup 不会阻止发送挂断信号以进行处理?

最佳答案

TL;DR

首先检查signal.Ignored():

if !signal.Ignored(unix.SIGHUP) {
    signal.Notify(sigs, unix.SIGHUP)
}

tkausl's comment有正确答案:运行:

nohup ./build_linux

从命令行启动./build_linux程序,并将SIGHUP设置为SIG_IGN(所有这些信号名称都是通用Linux名称,而不是 Go 包名称)。如果您为 SIGHUP 安装自己的处理程序,则会覆盖 SIGHUP 的当前设置。

一般来说,在 Unix/Linux 程序中,正确的模式是在安装 signal-catch 之前(或作为安装过程的一部分)测试信号是否当前被忽略功能。如果信号被忽略,则将其恢复为被忽略。

为了使这个过程完全可靠,最有效的正确模式是:

  • 阻止信号(也许是所有信号);
  • 安装任何所需的处理程序,该处理程序返回信号的当前配置;
  • 如果当前处置是 SIG_IGN,则将处置返回给 SIG_IGN
  • 释放信号。

持有和释放是通过 Unix/Linux sigprocmaskpthread_sigmask 系统调用完成的。使用哪一种取决于您是否使用线程。 Go 当然使用线程;参见,例如this patch到 2013 年的 Cgo 运行时启动(修复 issue #6811 )。

从 Go 1.11 开始,引入了 signal.Ignored ,您可以使用它,因为 Go 运行时已经在启动时完成了所有适当的保持/设置和测试/恢复序列,并缓存了结果。 绝对应该将其用于SIGHUP,以便遵守nohup约定。人们通常应该将其用于 SIGINT 和其他键盘信号,并且几乎1没有理由将其用于所有信号。< sup>1


1Jenkins,或者至少是 Jenkins 的某些版本,显然(错误地)将运行测试套件时启动时忽略的所有信号设置为忽略。

关于linux - 为什么即使使用 nohup 也能捕获挂断信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64479821/

相关文章:

linux - 导航多个文件 vi 编辑器

linux - 安装链接在一起的多个文件夹

Golang 泛型 - 简单用例

string - Go 语言 : A way to tokenize a string

networking - SetWriteDeadline有什么用

linux - 在 RPM 存储库中识别 RPM 包最新版本的过程是什么?

c - 信号和SIGCHLD,它有什么作用呢?

javascript - 在 Windows 中调试 Geddy Node.js 应用程序

c++ - 原子 "check signal and enter system call"操作

linux - 如何通过 Gnu Screen 中的键绑定(bind)执行脚本?