使用 pipe 在程序正文中捕获和处理信号
我的上一篇文章研究了一下如何在程序的正文(而不是信号处理函数)中捕获和处理信号。当时用的方案是 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 出来试试看。
有什么问题,欢迎告诉我~~~~
使用 pipe 在程序正文中捕获和处理信号相关推荐
- iOS 中捕获程序崩溃日志
iOS开发中遇到程序崩溃是很正常的事情,如何在程序崩溃时捕获到异常信息并通知开发者,是大多数软件都选择的方法.下面就介绍如何在iOS中实现: 1. 在程序启动时加上一个异常捕获监听,用来处理程序崩溃时 ...
- 从键盘输入两个数作为除数和被除数。要求程序中捕获NumberFormatException 异常和ArithmeticException 异常, 而且无论在哪种情况下,“程序执行结束”这句话都会在控制
编写应用程序,从键盘输入两个数作为除数和被除数.要求程序中捕获NumberFormatException 异常和ArithmeticException 异常, 而且无论在哪种情况下,"程序执 ...
- Python程序运行中出现异常错误的捕获语法——try、except和finally
文章目录 01. 异常的概念 02. 捕获异常 2.1 简单的捕获异常语法 简单异常捕获演练 -- 要求用户输入整数 2.2 错误类型捕获 异常类型捕获演练 -- 要求用户输入整数 捕获未知错误 2. ...
- 编写应用程序,从命令行传入两个整型数作为除数和被除数。要求程序中捕获NumberFormatException 异常和ArithmeticException异常,而且无论在哪种情况下,“总是被执行
package com.bw.tryCatch;import java.util.Scanner;public class zuoYe1 {// 编写应用程序,从命令行传入两个整型数作为除数和被除数. ...
- python捕获所有异常状态_如何在scrapy中捕获并处理各种异常
前言 使用scrapy进行大型爬取任务的时候(爬取耗时以天为单位),无论主机网速多好,爬完之后总会发现scrapy日志中"item_scraped_count"不等于预先的种子数量 ...
- 在C#代码中应用Log4Net(四)在Winform和Web中捕获全局异常
毕竟人不是神,谁写的程序都会有bug,有了bug不可怕,可怕的是出错了,你却不知道错误在哪里.所以我们需要将应用程序中抛出的所有异常都记录起来,不然出了错,找问题就能要了你的命.下面我们主要讨论的是如 ...
- Identifying Patch Correctness in Test-Based Program Repair--基于测试的程序修复中补丁正确性的识别
Identifying Patch Correctness in Test-Based Program Repair–基于测试的程序修复中补丁正确性的识别 摘要 近年来,基于测试的程序自动修复引起了广 ...
- 小程序开发过程中常见问题[微信小程序、支付宝小程序]
小程序开发过程中常见问题[微信小程序.支付宝小程序] 正文 一.样式中如何使用background-image呢? background-image支持网络的图片链接或者base64 二.使用自适应单 ...
- sigterm信号_详解如何在 docker 容器中捕获信号
概述 玩过docker的朋友可能都使用过 docker stop 命令来停止正在运行的容器,有些会使用 docker kill 命令强行关闭容器或者把某个信号传递给容器中的进程.这些操作的本质都是通过 ...
最新文章
- 关于Visual Studio2019的4996错误警告解决方法
- 2015/09/09夜晚js继续学习
- socketserver
- 求职及学习心情文章收集
- ASP.NET跨平台实践:无需安装Mono的Jexus“独立版”
- 图嵌入综述 (arxiv 1709.07604) 译文第一、二章
- Linux后台进程(和jobs、bg、fg)
- Kubernetes v1.19 正式发布!更新 33 项功能
- Linux命令解释之du
- 【机器学习】输出层的设计
- 使用ggplot2画图
- TFS与Git结合进行代码管理
- TripMode 管理 App 网络数据使用情况
- linux 如何开启shell,linux下开启Shell命令
- 软件测试必须知道的精华总结
- 清理window日志垃圾.bat
- js获取浏览器的宽度和高度
- python机器学习分析影响房价的主要因素
- CS231A:Vanishing Points and Lines
- 荣誉加持,驭势科技近期斩获奖项回顾
热门文章
- BILIBILI 高并发实时弹幕系统的实战之路 | 架构师实践日
- jsoncpp的输出顺序
- libevent中的基本数据结构
- HDU2018 母牛的故事
- linux03:系统常用的命令
- iOS数据存储简要笔记
- Python之路,day3-Python基础
- UNIX网络编程——客户/服务器程序设计示范(一)
- Windows Phone 7 Image Controller: Zoom In, Zoom Out, and Rotate (WP 7 图像控制器:放大,缩小,旋转)...
- GPass:GNOME 暗码治理器