首先来看一下一个简单的信号处理的例子
package main
import (
"fmt"
"os"
"os/signal"
)
func main() {
c := make(chan os.Signal, 1) # watch this
signal.Notify(c, os.Interrupt)
s := <-c
fmt.Println("Got signal:", s)
}
首先创建一个容纳信号对象的channel,channel的长度为1。
然后使用Notify注册信号处理,将Interrupt信号和channel关联起来。
进程挂在那里休眠,直到收到一个ctrl+c触发了Interrupt信号,channel里就会被塞进一条信号对象,<-c就会返回,打印信号对象然后退出程序。
上面这个例子是官方文档里提供的一个信号处理的简单例子。
值得注意的是这里的channel是非阻塞型channel,长度为1。那能不能是非阻塞型channel呢,能不能是长度为N的阻塞型channel呢?
我们先看看官方的文档里怎么说的
文档里的relay这个单词很有意思,它的英文是传达、转播,有点像代收的意思。
Notify会使得参数c[channel]来代收输入信号。如果信号参数sig未提供,就会代收所有类型的信号。否则只代收参数里提供的信号类型。
信号代收是非阻塞的,什么意思呢?
如果channel满了,被代收的信号就会被抛弃,因为没有空间容纳了。代收的过程等价于
select {
case c<-sig:
default:
}
如果channel的长度为1,当一连串的信号同时到达,只会有第一个信号会被代收,如果channel消费者没有来得及处理的话。
如果channel的长度为0,信号可能会丢失。比如下面的代码
package main
import (
"fmt"
"os"
"os/signal"
"time"
)
func main() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
time.Sleep(5 * time.Second)
s := <-c
fmt.Println("Got signal:", s)
}
我们在程序Sleep的时候狂按ctrl+c持续2秒,然后等待到5秒的Sleep结束,你会发现程序依然挂在那里,不会退出,这时需要再按一下ctrl+c才会退出。
阅读更多相关文章,关注知乎专栏【码洞】
有疑问加站长微信联系(非本文作者)