Golang中的信號處理
信號類型
個平臺的信號定義或許有些不同。下面列出了POSIX中定義的信號。
Linux 使用34-64信號用作實(shí)時(shí)系統(tǒng)中。
命令 man 7 signal 提供了官方的信號介紹。
在POSIX.1-1990標(biāo)準(zhǔn)中定義的信號列表
| 信號 | 值 | 動作 | 說明 |
|---|---|---|---|
| SIGHUP | 1 | Term | 終端控制進(jìn)程結(jié)束(終端連接斷開) |
| SIGINT | 2 | Term | 用戶發(fā)送INTR字符(Ctrl+C)觸發(fā) |
| SIGQUIT | 3 | Core | 用戶發(fā)送QUIT字符(Ctrl+/)觸發(fā) |
| SIGILL | 4 | Core | 非法指令(程序錯誤、試圖執(zhí)行數(shù)據(jù)段、棧溢出等) |
| SIGABRT | 6 | Core | 調(diào)用abort函數(shù)觸發(fā) |
| SIGFPE | 8 | Core | 算術(shù)運(yùn)行錯誤(浮點(diǎn)運(yùn)算錯誤、除數(shù)為零等) |
| SIGKILL | 9 | Term | 無條件結(jié)束程序(不能被捕獲、阻塞或忽略) |
| SIGSEGV | 11 | Core | 無效內(nèi)存引用(試圖訪問不屬于自己的內(nèi)存空間、對只讀內(nèi)存空間進(jìn)行寫操作) |
| SIGPIPE | 13 | Term | 消息管道損壞(FIFO/Socket通信時(shí),管道未打開而進(jìn)行寫操作) |
| SIGALRM | 14 | Term | 時(shí)鐘定時(shí)信號 |
| SIGTERM | 15 | Term | 結(jié)束程序(可以被捕獲、阻塞或忽略) |
| SIGUSR1 | 30,10,16 | Term | 用戶保留 |
| SIGUSR2 | 31,12,17 | Term | 用戶保留 |
| SIGCHLD | 20,17,18 | Ign | 子進(jìn)程結(jié)束(由父進(jìn)程接收) |
| SIGCONT | 19,18,25 | Cont | 繼續(xù)執(zhí)行已經(jīng)停止的進(jìn)程(不能被阻塞) |
| SIGSTOP | 17,19,23 | Stop | 停止進(jìn)程(不能被捕獲、阻塞或忽略) |
| SIGTSTP | 18,20,24 | Stop | 停止進(jìn)程(可以被捕獲、阻塞或忽略) |
| SIGTTIN | 21,21,26 | Stop | 后臺程序從終端中讀取數(shù)據(jù)時(shí)觸發(fā) |
| SIGTTOU | 22,22,27 | Stop | 后臺程序向終端中寫數(shù)據(jù)時(shí)觸發(fā) |
在SUSv2和POSIX.1-2001標(biāo)準(zhǔn)中的信號列表:
| 信號 | 值 | 動作 | 說明 |
|---|---|---|---|
| SIGTRAP | 5 | Core | Trap指令觸發(fā)(如斷點(diǎn),在調(diào)試器中使用) |
| SIGBUS | 0,7,10 | Core | 非法地址(內(nèi)存地址對齊錯誤) |
| SIGPOLL | Term | Pollable event (Sys V). Synonym for SIGIO | |
| SIGPROF | 27,27,29 | Term | 性能時(shí)鐘信號(包含系統(tǒng)調(diào)用時(shí)間和進(jìn)程占用CPU的時(shí)間) |
| SIGSYS | 12,31,12 | Core | 無效的系統(tǒng)調(diào)用(SVr4) |
| SIGURG | 16,23,21 | Ign | 有緊急數(shù)據(jù)到達(dá)Socket(4.2BSD) |
| SIGVTALRM | 26,26,28 | Term | 虛擬時(shí)鐘信號(進(jìn)程占用CPU的時(shí)間)(4.2BSD) |
| SIGXCPU | 24,24,30 | Core | 超過CPU時(shí)間資源限制(4.2BSD) |
| SIGXFSZ | 25,25,31 | Core | 超過文件大小資源限制(4.2BSD) |
Go中的Signal發(fā)送和處理
有時(shí)候我們想在Go程序中處理Signal信號,比如收到 SIGTERM 信號后優(yōu)雅的關(guān)閉程序(參看下一節(jié)的應(yīng)用)。
Go信號通知機(jī)制可以通過往一個channel中發(fā)送 os.Signal 實(shí)現(xiàn)。
首先我們創(chuàng)建一個os.Signal channel,然后使用 signal.Notify 注冊要接收的信號。
packagemain
import"fmt"
import"os"
import"os/signal"
import"syscall"
funcmain() {
// Go signal notification works by sending `os.Signal`
// values on a channel. We'll create a channel to
// receive these notifications (we'll also make one to
// notify us when the program can exit).
sigs := make(chanos.Signal,1)
done := make(chanbool,1)
// `signal.Notify` registers the given channel to
// receive notifications of the specified signals.
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
// This goroutine executes a blocking receive for
// signals. When it gets one it'll print it out
// and then notify the program that it can finish.
gofunc() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
done <- true
}()
// The program will wait here until it gets the
// expected signal (as indicated by the goroutine
// above sending a value on `done`) and then exit.
fmt.Println("awaiting signal")
<-done
fmt.Println("exiting")
}
go run main.go 執(zhí)行這個程序,敲入ctrl-C會發(fā)送 SIGINT 信號。 此程序接收到這個信號后會打印退出。

浙公網(wǎng)安備 33010602011771號