我正在尝试实现一个在 Go 中调用中断信号的函数。我知道如何使用
signal.Notify(interruptChannel, os.Interrupt)
拦截来自控制台的中断信号,但是,我找不到实际发送中断信号的方法。我发现您可以向进程发送信号,但我不确定这是否可以用于发送顶级中断信号。
有没有办法从 Go 函数内部发送中断信号,该信号可以被任何正在监听系统中断信号的东西捕获,或者 Go 不支持这种方式?
假设您正在使用类似的东西来捕获中断信号
var stopChan = make(chan os.Signal, 2)
signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
<-stopChan // wait for SIGINT
在代码中的任何位置使用下面的代码将中断信号发送到上面的等待部分。
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
或者如果您位于定义 stopChan 变量的同一包中。从而使其易于访问。你可以做到这一点。
stopChan <- syscall.SIGINT
或者你可以将stopChan定义为全局变量(将第一个字母大写即可达到相同的效果),然后你也可以从不同的包发送中断信号。
Stopchan <- syscall.SIGINT
使用 FindProcess、StartProcess 或其他方式获取进程。调用Signal发送中断:
err := p.Signal(os.Interrupt)
这会将信号发送到目标进程(假设调用进程有权这样做)并调用目标进程可能具有的 SIGINT 任何信号处理程序。
对于Windows情况,您可以使用以下方法:
func SendInterrupt() error {
d, e := syscall.LoadDLL("kernel32.dll")
if e != nil {
return fmt.Errorf("LoadDLL: %v", e)
}
p, e := d.FindProc("GenerateConsoleCtrlEvent")
if e != nil {
return fmt.Errorf("FindProc: %v", e)
}
r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(syscall.Getpid()))
if r == 0 {
return fmt.Errorf("GenerateConsoleCtrlEvent: %v", e)
}
return nil
}
我做了什么(实现优雅的关闭逻辑并“重新发送”捕获的
Signal
):
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)
... // in my case, all the latter is run in a go function
var err error
sig := <-sigs
signal.Stop(sigs)
close(sigs)
... // I invoked my shutdown logic here
syscallSig, ok := sig.(syscall.Signal)
if ok && (runtime.GOOS != "windows" || syscallSig != syscall.SIGINT) {
err = syscall.Kill(syscall.Getpid(), syscallSig)
} else {
if runtime.GOOS == "windows" {
err = syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
} else {
err = syscall.Kill(syscall.Getpid(), syscall.SIGINT)
}
}
if err != nil {
// panic to ensure the process shutdown won't be pending forever b/c I couldn't re-propagate the signal
panic(errUtil.ExplainIfErrorf(err, "emit a new signal"))
}