【问题标题】:do actions on end of execution在执行结束时执行操作
【发布时间】:2012-01-14 06:55:04
【问题描述】:

我有一个 http 服务器(使用 http.Handle 启动),我想做一些操作。

我该怎么做(在 linux 上)?在 ctrl-C 的情况下是否可以执行这些操作?

我不熟悉 unix 信号,所以答案可能很简单。

【问题讨论】:

  • 该代码可以作为单独的答案。我知道可以回答您自己的问题(甚至接受它!)归因于 kostix 将您发送到正确的方向也很好。
  • 好的,我会做一个单独的答案(有明确的归属)。

标签: signals go interrupt


【解决方案1】:

使用 kostix 回答,我构建了这段代码(现在适应 Go1)来捕获中断信号并在退出之前执行一些操作:

go func() {
    sigchan := make(chan os.Signal)
    signal.Notify(sigchan, os.Interrupt)
    <-sigchan
    log.Println("Program killed !")
    
    // do last actions and wait for all write operations to end
    
    os.Exit(0)
}()

// start main program tasks

【讨论】:

  • 为什么sigchan 的大小是10。我认为make(chan os.Signal, 1) 即大小1 也可以。如果我遗漏了什么,请告诉我。
  • @PrakashPandey 无缓冲的make(chan os.Signal) 在这种情况下工作得很好。
【解决方案2】:

您可以使用signal 包订阅 TERM 和 INT 信号。但请注意,这些信号仅在进程被显式终止时发送;正常退出(由进程本身启动)不涉及任何类型的信号。我认为正常退出只需在主程序中做一些事情(据说应该产生工作 goroutines 然后等待它们)。

阅读man 7 signal 了解有关 POSIX 信号的更多一般信息。

【讨论】:

    【解决方案3】:

    我想作者不仅对 Ctrl+C 感兴趣,而且为 Linux 提供更广泛的解决方案(对于 Windows 信号,请参阅x/sys/windows):

    package main
    
    import (
      "os"
      "os/signal"
      "syscall"
      "fmt"
    )
    
    func getFireSignalsChannel() chan os.Signal {
    
      c := make(chan os.Signal, 1)
      signal.Notify(c,
        // https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
        syscall.SIGTERM, // "the normal way to politely ask a program to terminate"
        syscall.SIGINT, // Ctrl+C
        syscall.SIGQUIT, // Ctrl-\
        syscall.SIGKILL, // "always fatal", "SIGKILL and SIGSTOP may not be caught by a program"
        syscall.SIGHUP, // "terminal is disconnected"
      )
      return c
    
    }
    
    func exit() {
      syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
    }
    
    func main() {
    
      exitChan := getFireSignalsChannel()
      input, err := os.Open("input.txt")
      if err != nil {
        panic(err)
      }
      defer input.Close()
      <-exitChan
      fmt.Println("Exiting!")
      return
      // All main deferreds executed here even in case of panic.
      // Non-main deferreds are not executed here.
    
    }
    

    附:没有信号处理os.Exit

    Ctrl+C 上使用此配置或在接收到其他信号时,程序会将os.Signal 推入通道exitChan,这将取消阻塞&lt;-exitChan 操作,main 函数将继续执行最后几行,然后返回,然后执行延迟函数。

    非主延迟

    对于非主延迟,您可以:

    1. 使用https://github.com/tebeka/atexit
    2. 将重要资源移动到全局数组中并在主延迟中释放它们。如果您不使用事务,则此解决方案并不完美:1)创建资源,2)添加到数组,-不应被退出中断。我猜还必须提供对切片的非并发读写访问权限。

    【讨论】:

    • 您的代码在 Windows 中也能正常运行。但是,除了直接在主函数中的defer 之外,我没有办法听到恐慌和 Go 崩溃。我在这里测试过 github.com/patarapolw/atexit>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 2016-03-31
    • 1970-01-01
    • 2011-06-25
    • 2019-05-29
    • 2017-10-17
    • 2013-08-27
    相关资源
    最近更新 更多