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 sigprocmask
或 pthread_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/