今天會用到 Go 裡面 Goroutine 跟 Channel 的語法,如果不太熟悉的話建議先看看我去年寫的 Go 語法 III
還記得昨天有提到 Shell 要負責 轉發 Signal 嗎,以下面這個 ping google.com
的例子來說,因為目前 Gosh 沒有做轉發 Signal 的動作,所以按了 <Ctrl>-C
會導致整個 Shell 被關掉而不只是 ping
被終止
昨天有說到在按下 <Ctrl>-C
時 Terminal 會 發送 SIGINT(中斷訊號) 給 Shell,這時 Shell 如果不去處理 Signal 的話就會觸發 SIGINT 的預設行為,導致 Shell 被關掉
面對 Signal 就像打躲避球一樣,當一顆球衝著你來而且避無可避的情況下,你要嘛接起來否則就是被打死。所以為了防止 Shell 被 SIGINT 關掉,Shell 自己 必須實作一個 Signal Handler 去接 Signal
signal.Notify(c chan<- os.Signal, sig ...os.Signal)
Notify
是用來指定 當有 Signal 進來時,要把 Signal 放在哪個 Channel 等待處理,指定之後新進來的 Signal 就會到 Channel 裡面排隊等著被處理,就像你去便利商店買東西一樣
func main()
// 這是之前寫的 initialize(讀取 .goshrc)
initialize()
// 程式一開始馬上初始化一個 channel 叫做 signalCh
// 等等會用來裝系統送來的 signal
signalCh := make(chan os.Signal)
// 用 Notify 監聽 SIGINT 訊號
// 當有 SIGINT 進來時會進到 signalCh 排隊
signal.Notify(signalCh, syscall.SIGINT)
// 寫一個 signal 的 handler
handleSignals := func() {
for {
// 當有新的 signal 進來時 Shell 把他接起來
sig := <-signalCh
// 並且輸出是哪一種 Signal
// (這邊只監聽 SIGINT 所以只會收到 interrupt)
fmt.Println("Received signal:", sig)
}
}
// 平常程式是一行一行跑,但 Signal 隨時會進來
// 所以要開一個 goroutine(Thread) 專門等待 Signal 進來
go handleSignals()
// ...
}
現在 Shell 已經不會被接踵而來的 <Ctrl>-C
打死了,因為所有的 SIGINT 都會被 Shell 接住,並且輸出 Received signal: interrupt
今天成功讓 Shell 接住 Signal 了,但要讓 <Ctrl>-C
可以終止 Process 的話必須把 Signal 轉發給正在執行的 Process 才行,所以明天就要來實作轉發 Signal 的部分