在执行结束时执行操作

huangapple go评论96阅读模式
英文:

do actions on end of execution

问题

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

我该如何在Linux上进行这些操作?在按下ctrl-C的情况下,是否可以执行这些操作?

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

英文:

I have an http server (launched using http.Handle) and I would like to do some operations.

How can I do that (on linux) ? Is it possible to do those operations in case of a ctrl-C ?

I'm not familiar with unix signals so the answer may be trivial.

答案1

得分: 24

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

go func() {
    sigchan := make(chan os.Signal)
    signal.Notify(sigchan, os.Interrupt)
    <-sigchan
    log.Println("程序被终止!")

    // 执行最后的操作并等待所有写操作结束

    os.Exit(0)
}()

// 开始主程序任务
英文:

Using kostix answer, I built this code (now adapted to Go1) to catch the interrupt signal and do some operations before exiting :

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

// start main program tasks

答案2

得分: 4

你可以使用signal包订阅TERM和INT信号。但请注意,这些信号只在进程被显式地终止时发送;正常退出(由进程自身发起)不涉及任何信号。我认为对于正常退出,只需在主例程中执行一些操作(假设应该生成工作协程,然后等待它们)。

阅读man 7 signal以获取有关POSIX信号的更一般信息。

英文:

You can subscribe to the TERM and INT signals using the signal package. But note that these signals are only sent when the process is killed explicitly; normal exit (initiated by the process itself) does not involve any sort of signals. I think for normal exit just do something in the main routine (which supposedly should spawn worker goroutines and then wait on them).

Read man 7 signal for more general info on POSIX signals.

答案3

得分: 4

我假设作者不仅对<kbd>Ctrl+C</kbd>感兴趣,还为Linux提供了更广泛的解决方案(有关Windows信号,请参阅x/sys/windows):

<!-- language: lang-go -->

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, // “正常请求程序终止的方式”
    syscall.SIGINT, // Ctrl+C
    syscall.SIGQUIT, // Ctrl-\
    syscall.SIGKILL, // “始终致命”,“SIGKILL和SIGSTOP可能无法被程序捕获”
    syscall.SIGHUP, // “终端断开连接”
  )
  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
  // 所有主要的延迟函数都在这里执行,即使发生恐慌也是如此。
  // 非主要的延迟函数不会在这里执行。

}

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

通过这个配置,在<kbd>Ctrl+C</kbd>或接收到其他信号时,程序将把os.Signal推入通道exitChan,这将解除&lt;-exitChan操作的阻塞,main函数将继续执行最后的代码行,然后返回,然后执行延迟函数。

非主要的延迟函数

对于非主要的延迟函数,您可以:

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

I suppose author is interested not only in <kbd>Ctrl+C</kbd> and offer more broad solution for Linux (for Windows signals see x/sys/windows):

<!-- language: lang-go -->

package main

import (
  &quot;os&quot;
  &quot;os/signal&quot;
  &quot;syscall&quot;
  &quot;fmt&quot;
)

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, // &quot;the normal way to politely ask a program to terminate&quot;
    syscall.SIGINT, // Ctrl+C
    syscall.SIGQUIT, // Ctrl-\
    syscall.SIGKILL, // &quot;always fatal&quot;, &quot;SIGKILL and SIGSTOP may not be caught by a program&quot;
    syscall.SIGHUP, // &quot;terminal is disconnected&quot;
  )
  return c

}

func exit() {
  syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
}

func main() {

  exitChan := getFireSignalsChannel()
  input, err := os.Open(&quot;input.txt&quot;)
  if err != nil {
    panic(err)
  }
  defer input.Close()
  &lt;-exitChan
  fmt.Println(&quot;Exiting!&quot;)
  return
  // All main deferreds executed here even in case of panic.
  // Non-main deferreds are not executed here.

}

P.S. None of signals handles os.Exit.

With this configuration on <kbd>Ctrl+C</kbd> or on receiving other signal program will push os.Signal into channel exitChan which will unblock &lt;-exitChan operation and the main function will continue execution on the final lines, then return, then execute deferred functions.

Non-Main Deferreds

For non-main deferred you may:

  1. Use https://github.com/tebeka/atexit
  2. Move important resources into global array and release them in a main deferred. This solution is not perfect if you don't use transaction: 1) create resource, 2) add to array, -- which shouldn't be interrupted by exit. Also non-concurrent read-write access to a slice must be provided I guess.

huangapple
  • 本文由 发表于 2011年12月7日 01:08:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/8403862.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定