Go:gsignal,信号大师

ℹ️ 本文基于Go 1.13。

signal 包提供了信息处理器并允许Go程序与传入的信息进行交互。让我们在深入内部前先从listener(监听者)开始。

订阅

信号的订阅是通过通道完成的。这是一个监听任何中断信号或者调整终端大小的程序示例。

每一个os.Signal 通道监听它自己的事件集。这是上面例子里订阅工作流的图:

Go还为通道提供了停止通知的功能Stop(os.Signal) 或者忽略信号的功能Ignore(...os.Signal)

该程序不能被CTRL+C 中断并且永远不会停止,因为在第二次从该通道接收之前,该通道已停止监听用于终端调整大小的信号。现在让我们看一下处理传入信号的listenerprocess是如何构建的。

gsignal

在初始阶段,signal生成一个goroutine,该goroutine循环运行并充当处理信号的消费者。此循环将一直休眠直到得到通知。这是第一步:

然后当一个信号程序时候,信号处理程序将委托一个特殊的goroutine gsignal 来处理。这个goroutine使用固定的且无法增长的较大栈(32k,以满足不同操作系统的需求)。每个线程M都有一个内部 gsignal goroutine来处理这些信号。这是更新的图:

gsignal分析信号检查是否可处理,并唤醒睡眠的goroutine并将信号发送到队列:

同步信号,类似SIGBUSSIGFPE ,无法被管理,将会被转换成panic

然后,此循环goroutine 可以对其进行处理。它会查找首先订阅该事件的通道,然后把信号推送给它们:

循环处理信号的goroutine可以通过go tool trace 可视化:

gsignal锁定或者阻塞会使信号处理陷入困境。由于其固定大小也无法再分配内存。这也是为什么信号处理链中会有两个独立goroutine的重要性:一个负责处理到达信号的排队,另一个在同一队列中循环处理他们。

现在,我们可以使用新组件更新第一部分的说明:


欢迎订阅我的公众号,文章更新早知道

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据