golang中對(duì)信號(hào)的處理主要使用os/signal包中的兩個(gè)方法:一個(gè)是notify方法用來(lái)監(jiān)聽(tīng)收到的信號(hào)硬梁;一個(gè)是 stop方法用來(lái)取消監(jiān)聽(tīng)吉懊。
Notify函數(shù)
原型:
func Notify(c chan<- os.Signal, sig …os.Signal)
說(shuō)明:
該函數(shù)會(huì)將進(jìn)程收到的系統(tǒng)Signal轉(zhuǎn)發(fā)給channel c,轉(zhuǎn)發(fā)哪些信號(hào)由該函數(shù)的可變參數(shù)決定诞外,如果你沒(méi)有傳入sig參數(shù),那么Notify會(huì)將系統(tǒng)收到的所有信號(hào)轉(zhuǎn)發(fā)給c。
使用:
1.監(jiān)聽(tīng)全部信號(hào)
package main
import (
"fmt"
"os"
"os/signal"
)
func main() {
//創(chuàng)建chan
c := make(chan os.Signal, 1) //buffered channel
//監(jiān)聽(tīng)所有信號(hào)
signal.Notify(c)
//阻塞直到有信號(hào)傳入
fmt.Println("啟動(dòng)")
s := <-c
fmt.Println("退出信號(hào)", s)
}
2.監(jiān)聽(tīng)指定信號(hào)
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2)
則Go只會(huì)關(guān)注你傳入的Signal類(lèi)型矾兜,其他Signal將會(huì)按照默認(rèn)方式處理,大多都是進(jìn)程退出患久。
因此你需要在Notify中傳入你要關(guān)注和處理的Signal類(lèi)型椅寺,也就是攔截它們,提供自定義處理函數(shù)來(lái)改變它們的行為蒋失。
3.優(yōu)雅退出go守護(hù)進(jìn)程
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
// 優(yōu)雅退出go守護(hù)進(jìn)程
func main() {
//創(chuàng)建監(jiān)聽(tīng)退出chan
c := make(chan os.Signal)
//監(jiān)聽(tīng)指定信號(hào) ctrl+c kill
signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
go func() {
for s := range c {
switch s {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
fmt.Println("退出", s)
ExitFunc()
case syscall.SIGUSR1:
fmt.Println("usr1", s)
case syscall.SIGUSR2:
fmt.Println("usr2", s)
default:
fmt.Println("other", s)
}
}
}()
fmt.Println("進(jìn)程啟動(dòng)...")
sum := 0
for {
sum++
fmt.Println("sum:", sum)
time.Sleep(time.Second)
}
}
func ExitFunc() {
fmt.Println("開(kāi)始退出...")
fmt.Println("執(zhí)行清理...")
fmt.Println("結(jié)束退出...")
os.Exit(0)
}
注意:
- chan os.Signal 一般是帶緩沖的(不帶也行)返帕,緩沖大小一般設(shè)置為和監(jiān)聽(tīng)信號(hào)種類(lèi)一致,這樣被監(jiān)聽(tīng)信號(hào)的重復(fù)遞達(dá)可能會(huì)丟失信號(hào)(不確定)篙挽。