如何在Go语言中捕获任意UNIX信号

htzpubme  于 2022-11-04  发布在  Unix
关注(0)|答案(2)|浏览(171)

我可以用signal package在go中捕获信号,但如何捕获从34(SIGRTMIN)到64(SIGRTMAX)的信号(包括link)呢?Golang称它们为“信号34”、“信号64”等,但这超出了重点。当我运行“pkill -34”时,我希望我的应用程序注意到它。
我可以在捕获所有信号时捕获它们:

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan)

然而,我不想捕捉所有的信号,我只想那些我之前提到的。
我还意识到,我可以捕捉个人信号,如:

signal.Notify(sigChan, os.Interrupt, syscall.SIGPOOL, syscall.SIGCLD ...)

但这需要信号常数,而我找不到对应于我想捕捉的信号的常数,有什么想法吗?

vnjpjtjt

vnjpjtjt1#

  • 简短回答 *:

您可以只将新信号声明为syscall.Signal类型的类型化常量:

const (
    SIGRTMIN = syscall.Signal(0x22)
)
  • 详细答案(工作原理):*

signal.Notify函数签名为:

Notify(c chan<- os.Signal, sig ...os.Signal)

其中os.Signal是定义如下的接口:

// A Signal represents an operating system signal.
// The usual underlying implementation is operating system-dependent:
// on Unix it is syscall.Signal.
type Signal interface {
    String() string
    Signal() // to distinguish from other Stringers
}

通常,您会使用signal.Notify函数,如范例所示:

signal.Notify(sigChan, os.Interrupt, syscall.SIGPOOL, syscall.SIGCLD ...)

因此,如果我们在syscall包中检查这些常量的实现,我们会看到:

SIGKILL   = Signal(0x9)

其中,syscall包中的Signal是一个已定义的类型:

// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int

func (s Signal) Signal() {}

func (s Signal) String() string {
    // ... a few lines of code
}

它只是一个底层的int,带有一个无操作Signal()方法和Stringer实现。
因此,您可以通过转换任意int值,以相同的方式为您想要捕获的信号声明自己的常量:

const (
    SIGRTMIN = syscall.Signal(0x22)
)

signal.Notify(sigChan, SIGRTMIN, /* etc. */)
pjngdqdw

pjngdqdw2#

根据所提供的输入,我制作了一个小片段,以轻松捕获所有SIGRT信号:

package main

import (
    "fmt"
    "syscall"
    "os/signal"
    "os"
)

func getSIGRTchannel() chan os.Signal {
    sigChan := make(chan os.Signal, 1)
    sigArr := make([]os.Signal, 31)
    for i := range sigArr {
        sigArr[i] = syscall.Signal(i + 0x22)
    }
    signal.Notify(sigChan, sigArr...)
    return sigChan
}

func main() {
    c := getSIGRTchannel()
    // Block until a signal is received.
    for {
        s := <-c
        fmt.Println("Got signal:", s)
    }
}

要使用它,请在一个终端窗口中运行此程序,并从另一个终端窗口向它发送一些信号。

相关问题