iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 24
2

前言

今天會用到 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

實作

會用到的 function

  • 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()
    
    // ...
}

Demo

現在 Shell 已經不會被接踵而來的 <Ctrl>-C 打死了,因為所有的 SIGINT 都會被 Shell 接住,並且輸出 Received signal: interrupt

小結

View commit on Github

今天成功讓 Shell 接住 Signal 了,但要讓 <Ctrl>-C 可以終止 Process 的話必須把 Signal 轉發給正在執行的 Process 才行,所以明天就要來實作轉發 Signal 的部分

延伸閱讀


上一篇
Day23-Signal 訊號(一)
下一篇
Day25-Signal 訊號(三)
系列文
Gosh!原來用 Go 寫一個 Unix Shell 這麼簡單30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言