分享
  1. 首页
  2. 文章

Go:gsignal,信号的掌控者

lxbwolf · · 1867 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

![Illustration created for "A Journey With Go", made from the original Go Gopher, created by Renee French.](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/00.png) i️ *本文基于 Go 1.13。* `signal` 包提供了信号处理器,让我们的 Go 程序可以与发送来的信号进行交互。在进入内部细节之前,我们先来了解下 listener。 ## 订阅 对信号的订阅是通过通道实现的。下面是一个监听所有中断信号和终端大小改变信号的程序的例子: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/01.png) 每个 `os.Signal` 通道监听各自对应的事件。下面是前面例子订阅工作流的示意图: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/02.png) Go 也赋予了通道停止被通知的能力(`Stop(os.Signal)` 函数)和忽略信号的能力(`Ignore(...os.Signal)` 函数)。下面是两个函数的例子: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/03.png) 这个程序无法被 `CTRL + C` 中断,并且永远不会停止,因为在第二次从该通道接收信号之前,该通道已停止侦听终端调整大小的信号。现在我们来看下处理发送来的信号的 `listener` 和 `process` 两个阶段是如何内建的。 ## gsignal 在初始化阶段,`signal` 开启了一个在循环中运行的协程,作为处理信号的消费者。在循环被通知激活之前,一直处于睡眠状态。下面是第一步的示意图: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/04.png) 然后,当一个信号到达程序时,信号处理器把它代理到一个名为 `gsignal` 的专用协程。这个协程是用比较大的栈空间(32 K,目的是满足不同操作系统的不同需求)创建的,并且空间固定不能增长。每个线程(图片的 `M`)内部都有 `gsignal` 协程来处理信号。下面是更新后的示意图: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/05.png) `gsignal` 分析信号,检查信号是否可处理,在把信号发送到队列里时唤醒处于睡眠状态的协程。 ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/06.png) *`SIGBUS` 或 `SIGFPE` 等同步信号不能被管理,会被转为 panic* 然后,循环中的协程可以处理它。它首先找到订阅了这个事件的通道,再把信号推进通道: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/07.png) 通过工具 `go tool trace` 可以可视化对循环处理信号的协程的追踪过程。 ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/08.png) `gsignal` 的阻塞或锁会让信号处理陷入麻烦。由于它的栈空间固定,因此不能再申请内存。这就是在信号处理链中有两个独立的协程很重要的原因:一个协程用于在信号到达时尽快排列信号,另一个协程用循环处理该队列中的信号。 现在我们可以用新的组件来更新第一节的插图了: ![](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20200309-Go-gsignal-Master-of-Signals/09.png)

via: https://medium.com/a-journey-with-go/go-gsignal-master-of-signals-329f7ff39391

作者:Vincent Blanchon 译者:lxbwolf 校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

本文由 GCTT 原创翻译,Go语言中文网 首发。也想加入译者行列,为开源做一些自己的贡献么?欢迎加入 GCTT!
翻译工作和译文发表仅用于学习和交流目的,翻译工作遵照 CC-BY-NC-SA 协议规定,如果我们的工作有侵犯到您的权益,请及时联系我们。

欢迎遵照 CC-BY-NC-SA 协议规定 转载,敬请在正文中标注并保留原文/译文链接和作者/译者等信息。
文章仅代表作者的知识和看法,如有不同观点,请楼下排队吐槽


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1867 次点击
被以下专栏收入,发现更多相似内容
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏