资讯专栏INFORMATION COLUMN

使用 pipe 在程序正文中捕获和处理信号

NotFound / 1438人阅读

摘要:本文地址环境高级编程源码深度剖析使用和在程序正文中捕获和处理信号基本原理在设置捕获信号之前,首先创建一个通信通道。在中断处理函数中,将捕获到的信号数往这个通道内写入。大量的数据处理放在程序正文中,获取信号的方法很简单,只是。

我的上一篇文章研究了一下如何在程序的正文(而不是信号处理函数)中捕获和处理信号。当时用的方案是 sigprocmask()。但那个方法理论上是可能漏掉一些信号的。

真正安全的做法,是使用进程 / 线程间通信手段,在信号处理函数中向外发送信号,然后在程序正文中监听(epoll, select 等等)这些数据。

这其中是需要使用全局变量的,我目前还没有不使用全局变量的方案。

本文地址:https://segmentfault.com/a/1190000009280819

Reference & Related

《UNIX 环境高级编程》
libevent 源码深度剖析
使用 sigprocmask 和 sigpending 在程序正文中捕获和处理信号

基本原理

在设置捕获信号之前(signal()),首先创建一个通信通道。在中断处理函数中,将捕获到的信号数往这个通道内写入。而在程序正文中,则对这个通道进行读取,这样就可以实现在程序正文中捕获信号了。

这其实是参考了 “libevent 源码深度剖析” 里面所说的 libevent 实现 evsignal的方案。大家都知道,在信号处理函数中,我们一般不要调用 printf 等 stdio 库里的函数。原因请参照《UNIX 环境高级编程》中 “信号” 章的 “可重入函数” 小节。

而实现这个功能中最重要的 read / write 函数,是可以在信号处理函数中调用的!这就是本方案的原理基础。

优点

由于通信通道基本上是 FIFO 的,所以如果信号多次产生,程序正文也可以收到排队发来的数据,避免了错过多个的信号。

信号处理函数非常非常短,只需要调用一个 write() 并且写入极少的数据即可。

大量的数据处理放在程序正文中,获取信号的方法很简单,只是 read()。并且每次获取数据的长度是固定的:signum 的类型是 int,获取 sizeof(int) 字节的数据即可。

pipe 可以直接使用 read / write API 操作,可以方便地对接异步 I/O 库。

选择 pipe 的原因

“libevent 源码深度剖析” 中提到 libevent 使用的是 UNIX域socket(AF_UNIX)。这里我不使用这个方案,而用了 pipe,原因如下:

pipe 初始化和创建简单

pipe 的创建是非命名的,生存周期仅在进程内部,也不会出现多个进程使用相同架构,发生命名冲突的问题

AF_UNIX 是命名的,而且协议栈较为复杂,系统开销稍有些大

一般而言 pipe 是用在父子进程间通信用的,甚至在《UNIX 环境高级编程》中还原文提到 “单个进程中的管道几乎没有任何用处” 。我就哈哈大笑啦——在本文的应用场景下,实际上就是 pipe 为数不多的在单个进程之内的使用。

代码实现

我正在自己设计一个基于 epoll 的异步 I/O 库(GitHub 链接),目前已经实现了类似于 libevent 的普通 event 和 evsignal。如果对这个实现感兴趣的话,可以直接到我的工程里看代码。本文内容主要是 epEventSignal.c 文件里的实现。

主要的实际上也就是 epEventSignal_AddToBase() 函数啦。在这个函数的操作流程如下:

调用 pipe() 创建管道

设置 nonblock、closeonexec 选项

pipe[0] 赋值到全局变量中

使用 sigaction() 函数捕获信号。信号处理函数中,将信号值写入 pipe[0]

pipe[1] 注册入 epoll 中,捕获读事件

我在自己的简单测试程序 test_server.c 中捕获了两个信号,分别是 SIGQUIT(忽略,仅输出)和 SIGINT(触发 event loop 安全退出)。读者可以 checkout 出来试试看。

有什么问题,欢迎告诉我~~~~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/9969.html

相关文章

  • 使用 sigprocmask sigpending 程序正文捕获处理信号

    摘要:后续有说明屏蔽信号的含义的作用,主要就是屏蔽指定的信号。在程序正文处理信号这里所说的正文,指的是不在或中指定的中处理信号事件,而是在普通的程序流程能够中捕捉信号,并且处理信号。的线程安全问题前文提及如果发现为。 最近在尝试使用 epoll 写一个类似 libevent 的库。那么,如何像 libevent 一样,在 event loop 里加入对信号事件的观测呢?我查了一下资料,一个可...

    PAMPANG 评论0 收藏0
  • 基于 epoll 设计类似 libevent 的异步 I/O 库 - 接口

    摘要:支持三种事件文件事件或者称事件文件描述符事件。各参数说明如下当创建文件事件时,参数就是对应的文件描述符当创建信号事件时,则是信号码。接收事件的回调函数。获取到响应后,将自身事件清除掉。 这篇文章可以算是我在 GitHub 上一个工程的设计概要了。简要说明了该工程的设计思路以及技术要点。 本文章纯原创,没有参考资料。不过有设计过程中记录下的相关文章: 使用 pipe 在程序正文中捕获和处...

    Taste 评论0 收藏0
  • python模块之subprocess类与常量

    摘要:限于,可选的文件描述符序列,用于在父子进程间保持开放。如果设置了,表示派生的进程号子进程返回码,表示进程未终止。如果未捕获标准错误返回方法如果非,抛出异常异常模块的异常基类子进程执行超时。 常量 subprocess.DEVNULL:可传递给stdin, stdout, stderr参数的特殊值,意味着将使用特殊文件os.devnull重定向输入输出 subprocess.PIPE:可...

    Alan 评论0 收藏0
  • Node.js学习之路14——Process进程

    摘要:在中,只支持单线程。在这种场合下,如果能够使用多进程,则可以为每个请求分配一个进程,从而可以更好地使用服务器端的资源。进程进程对象的属性用于运行应用程序的可执行文件的绝对路径的版本号及其各依赖的版本号当前运行的平台用于读入标准输入流的对象。 Process 在Node.js中,只支持单线程。但是在应用程序中,如果只使用单线程进行操作,从接收请求开始到返回响应为止的这段时间内可能存在很长...

    darry 评论0 收藏0
  • 【备战春招/秋招系列】美团面经总结基础篇 (附详解答案)

    摘要:不同于个人面经,这份面经具有普适性。我在前面的文章中也提到了应该怎么做自我介绍与项目介绍,详情可以查看这篇文章备战春招秋招系列初出茅庐的程序员该如何准备面试。是建立连接时使用的握手信号。它表示确认发来的数据已经接受无误。 showImg(https://segmentfault.com/img/remote/1460000016972448?w=921&h=532); 该文已加入开源文...

    Leck1e 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<