【问题标题】:How to capture arbitrary UNIX signals in Go如何在 Go 中捕获任意 UNIX 信号
【发布时间】:2020-06-28 10:39:12
【问题描述】:

我可以使用signal package 捕获信号,但我如何捕获从 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 ...)

但这需要信号常量,我找不到与我想要捕获的信号相对应的常量。有什么想法吗?

【问题讨论】:

    标签: go unix signals


    【解决方案1】:

    简答

    您可以将新信号声明为类型为 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. */)
    

    【讨论】:

      【解决方案2】:

      --------------答案------ ---------

      感谢 [blackgreen][3] 解决了这个问题。

      我做了一个小sn-p来轻松捕获所有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)
          }
      }
      

      要玩它,在一个终端窗口中运行这个程序,然后从另一个终端窗口向它发送一些信号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-02
        • 1970-01-01
        • 2022-01-17
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 1970-01-01
        相关资源
        最近更新 更多