linux - 为什么即使使用 nohup 也会捕获挂断信号?
问题描述
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;博士
首先检查signal.Ignored()
:
if !signal.Ignored(unix.SIGHUP) {
signal.Notify(sigs, unix.SIGHUP)
}
长
tkausl 的评论有正确的答案:运行:
nohup ./build_linux
从命令行启动./build_linux
程序并SIGHUP
设置为SIG_IGN
(所有这些信号名称都是通用的 Linux 名称,而不是 Go 包名称)。如果您为 安装自己的处理程序SIGHUP
,这将覆盖 的当前设置SIGHUP
。
通常,在 Unix/Linux 程序中,正确的模式是在安装信号捕获函数之前(或作为其一部分)测试信号当前是否被忽略。如果信号被忽略,则将其恢复为被忽略。
为了使这个过程完全可靠,最有效的正确模式是:
- 推迟信号(可能是所有信号);
- 安装任何所需的处理程序,该处理程序返回信号的当前处置;
- 如果当前处置是
SIG_IGN
,将处置返回到SIG_IGN
; - 释放信号。
持有和释放是通过 Unix/Linuxsigprocmask
或pthread_sigmask
系统调用完成的。使用哪个取决于您是否使用线程。Go 当然使用线程;参见,例如,这个从 2013 年开始 Cgo 运行时启动的补丁(修复问题 #6811)。
自 Go 1.11 以来signal.Ignored
,您可以直接使用它,因为 Go 运行时已经在启动时完成了所有适当的保持/设置和测试/恢复序列,并缓存了结果。绝对应该使用它SIGHUP
来遵守nohup
约定。人们通常也应该将其用于SIGINT
其他键盘信号,并且几乎没有理由不将其用于所有信号。1
1 Jenkins,或者至少是 Jenkins 的某个或多个版本,显然(错误地)在运行测试套件时将所有信号设置为在启动时被忽略。
推荐阅读
- user-interface - Visual Studio - 折叠派生类隐藏继承类
- java - Spring MVC:未找到静态 URL,但资源 URL 有效
- c# - 使用 SharpZipLib 如何设置加密算法?
- python - 将具有 UV 映射纹理的 .obj/.blend 渲染为 .png 的最快简单方法
- tensorflow - tensorflow object api faster_rcnn_resnet101 训练图像调整大小
- javascript - Recaptcha on React 组件
- c# - C# LinqToExcel GetColumnName 第 n 行
- javascript - Reactjs, React, styled-components - Rebass 库基于对象文字的道具是否不需要重新渲染组件?
- python - 我想根据python中其他两个数组的条件定义一个数组
- spring - 带有 Zuul 代理和多个客户端(本机、移动、Web)的 Spring Boot Oauth2 SSO