信号是操作系统与正在运行的进程进行通信的基本方式。其中两种最常见的信号是SIGINT
和SIGTERM
。这两个信号将导致程序终止。
还有信号如SIGHUP
。SIGHUP
表示调用该进程的终端已经关闭,例如,程序可以通过该信号决定是否移动到后台执行。
Go提供了一种在应用程序收到信号时处理行为的方法。
处理操作系统信号
Golang 版本
1.12.1
前言
信号是操作系统与正在运行的进程进行通信的基本方式。其中两种最常见的信号是SIGINT
和SIGTERM
。这两个信号将导致程序终止。
还有信号如SIGHUP
。SIGHUP
表示调用该进程的终端已经关闭,例如,程序可以通过该信号决定是否移动到后台执行。
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
方法不会阻塞信号。这样信号就会被错过。为了避免丢失信号,最好创建缓冲通道。
注意,
SIGKILL
和SIGSTOP
信号可能不会被Notify
方法捕获,因此无法处理这些信号。