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