Go:gsignal,信号大师
ℹ️ 本文基于 Go 1.13。
signal
包提供了信息处理器并允许 Go 程序与传入的信息进行交互。让我们在深入内部前先从 listener(监听者)开始。
订阅
信号的订阅是通过通道完成的。这是一个监听任何中断信号或者调整终端大小的程序示例。
每一个os.Signal
通道监听它自己的事件集。这是上面例子里订阅工作流的图:
Go 还为通道提供了停止通知的功能Stop(os.Signal)
或者忽略信号的功能Ignore(...os.Signal)
。
该程序不能被CTRL+C
中断并且永远不会停止,因为在第二次从该通道接收之前,该通道已停止监听用于终端调整大小的信号。现在让我们看一下处理传入信号的listener
和process
是如何构建的。
gsignal
在初始阶段,signal
生成一个 goroutine,该 goroutine 循环运行并充当处理信号的消费者。此循环将一直休眠直到得到通知。这是第一步:
然后当一个信号程序时候,信号处理程序将委托一个特殊的 goroutine gsignal
来处理。这个 goroutine 使用固定的且无法增长的较大栈(32k,以满足不同操作系统的需求)。每个线程 M 都有一个内部 gsignal
goroutine 来处理这些信号。这是更新的图:
gsignal
分析信号检查是否可处理,并唤醒睡眠的 goroutine 并将信号发送到队列:
同步信号,类似SIGBUS
或SIGFPE
,无法被管理,将会被转换成 panic
然后,此循环 goroutine 可以对其进行处理。它会查找首先订阅该事件的通道,然后把信号推送给它们:
循环处理信号的 goroutine 可以通过go tool trace
可视化:
gsignal
锁定或者阻塞会使信号处理陷入困境。由于其固定大小也无法再分配内存。这也是为什么信号处理链中会有两个独立 goroutine 的重要性:一个负责处理到达信号的排队,另一个在同一队列中循环处理他们。
现在,我们可以使用新组件更新第一部分的说明:
本文首发于我的公众号:
版权声明: 本文为 InfoQ 作者【陈思敏捷】的原创文章。
原文链接:【http://xie.infoq.cn/article/25baf580a1b872b6989dfcdf1】。文章转载请联系作者。
评论