在执行结束时执行操作

时间:2011-12-06 17:08:45

标签: signals go interrupt

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

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

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

3 个答案:

答案 0 :(得分:16)

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

go func() {
    sigchan := make(chan os.Signal, 10)
    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

答案 1 :(得分:3)

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

阅读man 7 signal以获取有关POSIX信号的更多常规信息。

答案 2 :(得分:0)

我认为作者不仅对 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.

}

P.S。没有信号处理os.Exit

Ctrl + C 上进行此配置,或者在接收其他信号程序时,将os.Signal推入频道exitChan,这将取消阻止<-exitChan操作和{{ 1}}函数将在最后一行继续执行,然后返回,然后执行延迟函数。

非主要延期

对于非主延期,您可以:

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