?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
import "os/signal"
Overview
Index
Examples
封裝信號實現(xiàn)對輸入信號的訪問。
信號主要用于類 Unix 系統(tǒng)。有關(guān)在 Windows 和 Plan 9上使用此軟件包的信息,請參見下文。
信號 SIGKILL 和 SIGSTOP 可能不會被程序捕獲,因此不會受此軟件包影響。
同步信號是由程序執(zhí)行中的錯誤觸發(fā)的信號:SIGBUS,SIGFPE和SIGSEGV。這些只在程序執(zhí)行時才被認為是同步的,而不是在使用 os.Process.Kill 或 kill 程序或類似的機制發(fā)送時。一般來說,除了如下所述,Go 程序會將同步信號轉(zhuǎn)換為運行時恐慌。
其余信號是異步信號。它們不是由程序錯誤觸發(fā)的,而是從內(nèi)核或其他程序發(fā)送的。
在異步信號中,SIGHUP 信號在程序失去其控制終端時發(fā)送。當(dāng)控制終端的用戶按下中斷字符(默認為^ C(Control-C))時,發(fā)送 SIGINT 信號。當(dāng)控制終端的用戶按下退出字符時發(fā)送 SIGQUIT 信號,默認為^ \(Control-Backslash)。一般情況下,您可以通過按^ C來使程序簡單地退出,并且可以通過按^使堆棧轉(zhuǎn)儲退出。
默認情況下,同步信號被轉(zhuǎn)換為運行時恐慌。SIGHUP,SIGINT或SIGTERM信號導(dǎo)致程序退出。SIGQUIT,SIGILL,SIGTRAP,SIGABRT,SIGSTKFLT,SIGEMT或SIGSYS信號會導(dǎo)致程序以堆棧轉(zhuǎn)儲退出。SIGTSTP,SIGTTIN或SIGTTOU信號獲取系統(tǒng)默認行為(這些信號由外殼用于作業(yè)控制)。SIGPROF信號由 Go 運行時直接處理以實現(xiàn) runtime.CPUProfile 。其他信號將被捕獲,但不會采取任何行動。
如果 Go 程序以忽略 SIGHUP 或 SIGINT(信號處理程序設(shè)置為 SIG_IGN)啟動,它們將保持忽略。
如果 Go 程序是以非空信號掩碼開始的,那么通常將會受到尊重。然而,一些信號被明確地解除阻礙:在GNU / Linux上,同步信號,SIGILL,SIGTRAP,SIGSTKFLT,SIGCHLD,SIGPROF和信號32(SIGCANCEL)和33(SIGSETXID)(SIGCANCEL和SIGSETXID由glibc內(nèi)部使用)。由 os.Exec 或 os / exec包啟動的子進程將繼承修改的信號掩碼。
這個包中的函數(shù)允許程序改變 Go 程序處理信號的方式。
通知會禁用給定的一組異步信號的默認行為,而是通過一個或多個注冊的通道傳遞它們。具體來說,它適用于信號SIGHUP,SIGINT,SIGQUIT,SIGABRT和SIGTERM。它也適用于作業(yè)控制信號SIGTSTP,SIGTTIN和SIGTTOU,在這種情況下系統(tǒng)默認行為不會發(fā)生。它也適用于一些不會引起任何動作的信號:SIGUSR1,SIGUSR2,SIGPIPE,SIGALRM,SIGCHLD,SIGCONT,SIGURG,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGWINCH,SIGIO,SIGPWR,SIGSYS,SIGINFO,SIGTHR,SIGWAITING,SIGLWP,SIGFREEZE, SIGTHAW,SIGLOST,SIGXRES,SIGJVM1,SIGJVM2以及系統(tǒng)中使用的任何實時信號。請注意,并非所有這些信號都適用于所有系統(tǒng)。
如果程序在忽略 SIGHUP 或 SIGINT 的情況下啟動,并且任何一個信號都會調(diào)用 Notify,則將為該信號安裝一個信號處理程序,并且不會再被忽略。如果稍后為該信號調(diào)用 Reset 或 Ignore,或者在傳遞給 Notify 的所有通道上調(diào)用 Stop 以獲取該信號,則信號將再次被忽略。重置將恢復(fù)信號的系統(tǒng)默認行為,而忽略會導(dǎo)致系統(tǒng)完全忽略信號。
如果程序以非空信號掩碼開始,則一些信號將如上所述被明確地解除阻塞。如果 Notify 被呼叫阻塞信號,它將被解除阻塞。如果稍后對該信號調(diào)用 Reset,或者在傳遞給 Notify 的所有通道上調(diào)用 Stop,則該信號將再次被阻止。
當(dāng)一個 Go 程序?qū)懭胍粋€損壞的管道時,內(nèi)核將產(chǎn)生一個 SIGPIPE 信號。
如果程序尚未調(diào)用 Notify 來接收 SIGPIPE 信號,則行為取決于文件描述符編號。在文件描述符1或2(標準輸出或標準錯誤)上寫入損壞的管道將導(dǎo)致程序以 SIGPIPE 信號退出。在某些其他文件描述符上寫入損壞的管道將不會對 SIGPIPE 信號采取任何操作,并且寫入操作將失敗并顯示 EPIPE 錯誤。
如果程序調(diào)用 Notify 來接收 SIGPIPE 信號,則文件描述符號碼無關(guān)緊要。SIGPIPE 信號將被傳送到通知通道,并且寫入將失敗并出現(xiàn) EPIPE 錯誤。
這意味著,默認情況下,命令行程序的行為與典型的 Unix 命令行程序相同,而其他程序在寫入封閉網(wǎng)絡(luò)連接時不會因 SIGPIPE 而崩潰。
在包含非 Go 代碼(通常使用cgo或SWIG訪問的C / C ++代碼)的Go程序中,Go 的啟動代碼通常首先運行。它在非運行啟動代碼運行之前,按照 Go 運行時的預(yù)期配置信號處理程序。如果 non-Go 啟動代碼希望安裝自己的信號處理程序,則必須采取一定步驟才能保證Go運行正常。本節(jié)介紹這些步驟,以及 Go-Go 程序?qū)π盘柼幚砥髟O(shè)置的整體效果變化。在極少數(shù)情況下,非 Go 代碼可能在 Go 代碼之前運行,在這種情況下,下一節(jié)也適用。
如果 Go 程序調(diào)用的非 Go 代碼不會更改任何信號處理程序或掩碼,則行為與純 Go 程序的行為相同。
如果 non-Go 代碼安裝任何信號處理程序,則必須在 sigaction 中使用 SA_ONSTACK 標志。如果沒有收到信號,很可能會導(dǎo)致程序崩潰。Go 程序通常使用有限的堆棧運行,因此設(shè)置了一個備用信號堆棧。另外,Go 標準庫期望任何信號處理程序都將使用 SA_RESTART 標志。否則可能會導(dǎo)致某些庫調(diào)用返回“中斷的系統(tǒng)調(diào)用”錯誤。
如果 non-Go 代碼為任何同步信號(SIGBUS,SIGFPE,SIGSEGV)安裝信號處理程序,則應(yīng)該記錄現(xiàn)有的 Go 信號處理程序。如果這些信號在執(zhí)行 Go 代碼時發(fā)生,它應(yīng)該調(diào)用 Go 信號處理程序(無論執(zhí)行 Go 信號時發(fā)生的信號是否可以通過查看傳遞給信號處理程序的 PC 來確定)。否則,某些 Go 運行時恐慌不會按預(yù)期發(fā)生。
如果 non-Go 代碼為任何異步信號安裝信號處理程序,則它可以調(diào)用Go信號處理程序或不按照它選擇的方式。當(dāng)然,如果它不調(diào)用 Go 信號處理程序,則上述 Go 行為不會發(fā)生。這可能是 SIGPROF 信號的問題。
非 Go 代碼不應(yīng)該改變 Go 運行時創(chuàng)建的任何線程上的信號掩碼。如果 non-Go 代碼自己啟動新線程,它可以根據(jù)需要設(shè)置信號掩碼。
如果 non-Go 代碼啟動一個新線程,更改信號掩碼,然后調(diào)用該線程中的 Go 函數(shù),則 Go 運行時將自動解除某些信號的阻塞:同步信號SIGILL SIGTRAP SIGSTKFLT SIGCHLD SIGPROF SIGCANCEL和SIGSETXID。當(dāng) Go 函數(shù)返回時,非 Go 信號掩碼將被恢復(fù)。
如果 Go 信號處理程序是在未運行 Go 代碼的非 Go 線程上調(diào)用的,則處理程序通常會將該信號轉(zhuǎn)發(fā)給非 Go 代碼,如下所示。如果信號是 SIGPROF,則 Go 處理程序不執(zhí)行任何操作。否則,Go 處理程序會自行刪除,解除阻塞信號并再次提升,以調(diào)用任何非 Go 處理程序或缺省系統(tǒng)處理程序。如果程序沒有退出, Go 處理程序會自行重新安裝并繼續(xù)執(zhí)行程序。
當(dāng) Go 代碼使用諸如-buildmode = c-shared之類的選項構(gòu)建時,它將作為現(xiàn)有非 Go 程序的一部分運行。非 Go 代碼在 Go 代碼開始時可能已經(jīng)安裝了信號處理程序(當(dāng)使用 cgo 或 SWIG 時,這種情況也會發(fā)生在特殊情況下;在這種情況下,這里的討論適用)。對于-buildmode = c-archive,Go 運行時將在全局構(gòu)造函數(shù)時初始化信號。對于-buildmode = c-shared,Go 運行時將在共享庫加載時初始化信號。
如果 Go 運行時發(fā)現(xiàn) SIGCANCEL 或 SIGSETXID 信號(僅用于GNU / Linux)的現(xiàn)有信號處理程序,它將打開 SA_ONSTACK 標志,否則保持信號處理程序。
對于同步信號和 SIGPIPE,Go 運行時將安裝一個信號處理程序。它將保存任何現(xiàn)有的信號處理程序。如果同步信號在執(zhí)行非 Go 代碼時到達,Go 運行時將調(diào)用現(xiàn)有的信號處理程序而不是 Go 信號處理程序。
使用-buildmode = c-archive或-buildmode = c-shared構(gòu)建的Go代碼默認情況下不會安裝任何其他信號處理程序。如果存在現(xiàn)有的信號處理程序,Go 運行時將打開 SA_ONSTACK 標志,否則保持信號處理程序。如果 Notify 被調(diào)用為異步信號,則會為該信號安裝 Go 信號處理程序。如果稍后對該信號調(diào)用 Reset,則將重新安裝該信號的原始處理,如果有的話還原非 Go 信號處理程序。
不使用-buildmode = c-archive或-buildmode = c-shared構(gòu)建的 Go 代碼將為上面列出的異步信號安裝信號處理程序,并保存任何現(xiàn)有的信號處理程序。如果一個信號被傳送到一個非 Go 線程,它將按照上面描述的方式工作,除了如果有一個現(xiàn)有的非 Go 信號處理程序,該處理程序?qū)⒃谔嵘盘栔氨话惭b。
在 Windows 上,^ C(Control-C)或^ BREAK(Control-Break)通常會導(dǎo)致程序退出。如果通知被調(diào)用 os.Interrupt , ^ C 或 ^ BREAK 將導(dǎo)致 os.Interrupt 在通道上發(fā)送,并且程序不會退出。如果調(diào)用Reset,或在傳遞給 Notify 的所有通道上調(diào)用 Stop,則將恢復(fù)默認行為。
在計劃9中,信號具有類型 syscall.Note,這是一個字符串。使用 syscall.Note 調(diào)用通知將導(dǎo)致該值在通道上發(fā)送,當(dāng)該字符串發(fā)布為備注時。
func Ignore(sig ...os.Signal)
func Notify(c chan<- os.Signal, sig ...os.Signal)
func Reset(sig ...os.Signal)
func Stop(c chan<- os.Signal)
Notify
doc.go signal.go signal_unix.go
func Ignore(sig ...os.Signal)
忽略導(dǎo)致提供的信號被忽略。如果他們被程序收到,什么都不會發(fā)生。忽略任何先前通知提供的信號通知的效果。如果沒有提供信號,則所有輸入信號都將被忽略。
func Notify(c chan<- os.Signal, sig ...os.Signal)
通知會導(dǎo)致軟件包信號將輸入信號中繼到 c 。如果沒有提供信號,所有輸入信號將被中繼到 c 。否則,只有提供的信號會。
包信號不會阻止發(fā)送到 c:調(diào)用者必須確保 c 有足夠的緩沖空間來跟上預(yù)期的信號速率。對于僅用于通知一個信號值的通道,大小為1的緩沖區(qū)就足夠了。
允許使用相同的頻道多次調(diào)用通知:每個呼叫都會擴展發(fā)送到該頻道的一組信號。從集合中刪除信號的唯一方法是調(diào)用 Stop 。
可以使用不同的通道和相同的信號多次呼叫通知:每個通道獨立接收輸入信號的副本。
package mainimport ("fmt""os""os/signal")func main() {// Set up channel on which to send signal notifications.// We must use a buffered channel or risk missing the signal// if we're not ready to receive when the signal is sent. c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt)// Block until a signal is received. s := <-c fmt.Println("Got signal:", s)}
func Reset(sig ...os.Signal)
重設(shè)撤消任何先前呼叫的效果,以通知所提供的信號。如果沒有提供信號,所有信號處理程序?qū)⒈恢刂谩?/p>
func Stop(c chan<- os.Signal)
停止導(dǎo)致封裝信號停止將輸入信號中繼到 c 。它解除了以前使用 c 通知通知的效果。當(dāng)停止返回時,保證 c 將不會收到更多信號。