go基础库之处理操作系统信号

信号是操作系统与正在运行的进程进行通信的基本方式。其中两种最常见的信号是SIGINTSIGTERM。这两个信号将导致程序终止。

还有信号如SIGHUPSIGHUP表示调用该进程的终端已经关闭,例如,程序可以通过该信号决定是否移动到后台执行。

Go提供了一种在应用程序收到信号时处理行为的方法。

处理操作系统信号

Golang 版本

1.12.1

前言

信号是操作系统与正在运行的进程进行通信的基本方式。其中两种最常见的信号是SIGINTSIGTERM。这两个信号将导致程序终止。

还有信号如SIGHUPSIGHUP表示调用该进程的终端已经关闭,例如,程序可以通过该信号决定是否移动到后台执行。

Go提供了一种在应用程序收到信号时处理行为的方法。

实现

package main

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

func main() {

	// 创建将发送接收信号的通道。
	// 发送信号且通道未就绪时,
	// 通知不会阻止。因此最好创建
	// 缓冲通道。
	sChan := make(chan os.Signal, 1)

	// Notify 将捕获给定的信号并通过 sChan
	// 发送 os.Signal 值。如果参数中未指定
	// 信号,则匹配所有信号。
	signal.Notify(sChan,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)

	// 创建要等待信号处理的通道
	exitChan := make(chan int)
	go func() {
		signal := <-sChan
		switch signal {
		case syscall.SIGHUP:
			fmt.Println("终端已经关闭")
			exitChan <- 0

		case syscall.SIGINT:
			fmt.Println("该程序已被 CTRL+C 中断")
			exitChan <- 1

		case syscall.SIGTERM:
			fmt.Println("通过 SIGTERM 信号关闭")
			exitChan <- 1

		case syscall.SIGQUIT:
			fmt.Println("通过 SIGQUIT 信号关闭")
			exitChan <- 1
		}
	}()

	code := <-exitChan
	os.Exit(code)
}

运行 go run main.go,然后执行 CTRL + C 发送 SIGINT 信号

$ go run main.go
^C该程序已被 CTRL+C 中断

原理

应用在获取资源的时候,如果这个时候中断会发生资源泄漏。这个时候最好通过信号来采取一些必要的措施来释放资源。

signal包中的Notify方法将帮助我们处理接收到的信号。

如果在Notify方法中没有指定信号作为参数,那么该方法将捕获所有可能的信号。

注意,signal包的Notify方法通过sChan通道与goroutine通信。Notify然后捕获定义的信号并将其发送到goroutine进行处理。最后,使用exitChan解析进程的退出代码。

重要的是,如果指定的通道没有准备好,Notify方法不会阻塞信号。这样信号就会被错过。为了避免丢失信号,最好创建缓冲通道。

注意,SIGKILLSIGSTOP信号可能不会被Notify方法捕获,因此无法处理这些信号。