go与KeyboardInterrupt

背景

go没有传统的异常处理机制,
那么它是如何处理键盘来的Ctrl-C的?

信号观点

go将keyboard interrupt视为系统信号,而不是一个error或panic.并将通道作为载体.
若将信号转发的通道,可以在通道的另一端接收并处理信号.
若没有做任何事情(即没有将信号转发),则触发默认行为.

与传统try catch对应

  1. catch: 从通道中取出信号
  2. raise: 向通道中放入信号

而go多了对通道的管理

  1. signal.Notify(ch, 类型…), 将系统信号转发到ch
  2. signal.Stop(ch), 不再向ch转发系统信号

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import (
"fmt"
"os"
"os/signal"
"time"
)

func main() {
/* 接收信号 */
c := make(chan os.Signal)
// 将输入信号转发到c
// 没有列出信号类型,则表示所有类型
signal.Notify(c, os.Interrupt, os.Kill)
go func() {
sig := <-c // 传统方式是catch exception,而go只是取出信号
fmt.Printf("\nan os signal received [%v]\n", sig)
os.Exit(0)
}()

time.AfterFunc(time.Second*5, func() {
// 停止信号的转发,传统try catch结构无法完成
signal.Stop(c)
})

/* 发射信号 */
time.AfterFunc(time.Second*3, func() {
c <- os.Interrupt // 传统方式是直接raise exception,而go则是放入信号
})

living()
}

func living() {
for i := 0; i < 10; i++ {
fmt.Println(i)
time.Sleep(time.Second)
}
}

参考

  1. os/signal包