信号处理设计模式

问题

如何编写信号安全的应用程序?

Linux 应用程序安全性讨论

场景一:不需要处理信号

  • 应用程序实现单一功能,不需要关注信号
    • 如:数据处理程序,文件加密程序,科学计算程序

场景二:需要处理信号

  • 应用程序长时间运行,需要关注信号,并即使处理
    • 如:服务端程序,上位机程序

场景一:不需要信号处理 (单一功能应用程序)

场景二:需要处理信号 (长时间运行的应用)

同步方案

  • 通过标记同步处理信号,整个应用中只有一个执行流

异步方案

  • 专用任务处理,应用中存在多个执行流 (多线程应用)
  • 设置专用信号处理任务,其它任务忽略信号,专注功能实现

同步解决方案 (单任务)

信号处理逻辑与程序逻辑位于同一个上下文

  • 即:信号处理函数和主函数不存在资源竞争关系

方案设计一

  • 将任务分解为子任务(每个任务可对应一个函数)
  • 信号递达时,信号处理函数中仅标记递达状态
  • 子任务处理结束后,真正执行信号处理

同步方案示例一

存在的问题

由于给每个信号唯一的标记位置,因此,所有信号转变为不可靠信号;并且仅保留最近递达的信号信息

方案设计二

将任务分解为子任务 (每个任务可对应一个函数)

  • 创建信号文件描述符,并阻塞所有信号 (可靠信号递达前位于内核队列中)
  • 子任务处理结束后,通过 select 机制判断是否有信号需要处理
    • true => 处理信号 false => 等待超时

关键系统函数

#include <sys/select.h>

#include <sys/signalfd.h>

int signalfd(int fd, const sigset_t* mask, int flag);

int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

使用 signalfd() 处理信号

先屏蔽所有信号 (无法递达进程),之后为屏蔽信号创建文件描述符;当时机成熟,通过 read() 系统调用读取未决信号 (主动接收信号)

使用 select() 监听文件描述符

使用 select() 处理信号

存在的问题

由于使用了 select 机制,即便没有信号需要处理,也需要等待 select 超时,任务实时性受到影响

异步解决方案 (多任务)

使用独立任务处理信号,程序逻辑在其他任务中执行

即:通过多线程分离信号处理与程序逻辑

  • 主线程:专用于信号处理
  • 其他线程:完成程序功能

多线程信号处理

信号的发送目标是进程,而不是某个特定的线程

发送给进程的信号仅递送给一个进程

内核从不会阻塞目标信号的线程中随机选择

每个线程拥有独立的信号屏蔽掩码

异步解决方案 (多任务)

主线程:对目标信号设置信号处理的方式

  • 当信号递达进程时,只可能时主线程进行信号处理

其他线程:首先屏蔽所有可能的信号,之后执行任务代码

  • 无法接收到信号,不具备信号处理能力

进程与线程

进程:应用程序的一次加载执行 (系统执行资源分配的基本单位)

线程:进程中的程序执行流

  • 一个进程中可以存在多个线程 (至少存在一个线程)
  • 每个线程执行不同的任务 (多个线程可并行执行)
  • 同一个进程中的多个线程共享进程的系统资源

Linux 多线程 API 函数

头文件:#include<pthread.h>

线程创建函数:int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);

  • thread:pthread_t 变量的地址,用于返回线程标识
  • attr:线程的属性,可设置为 NULL,即:使用默认属性
  • start_routine:线程入口函数
  • arg:线程入口函数参数

线程标识:

  • pthread_t pthread_self(void);
  • 获取当前线程的 ID 标识

线程等待:

  • int pthread_join(pthread_t thread, void** retval);
  • 等待目标线程执行结束

多线程编程示例

异步方案示例 -- 主线程

异步方案示例 -- 任务线程

信号设计模式小结

多数模式不需要处理信号,因此可直接屏蔽信号

需要处理信号的程序,重点考虑信号安全性问题

  • 同步处理方案,通过设计让任务代码和信号处理代码交替执行
    • 问题:信号处理是否及时?任务执行是否实时?
  • 异步处理方案,任务代码与信号处理代码位于不同执行流
    • 问题:将信号安全性问题转换为线程安全性问题
    • 因此,程序本身是否能做到线程安全?
相关推荐
Ribou23 分钟前
Ubuntu 24.04.2安装k8s 1.33.4 配置cilium
linux·ubuntu·kubernetes
tan180°1 小时前
Boost搜索引擎 网络库与前端(4)
linux·网络·c++·搜索引擎
Mr. Cao code2 小时前
Docker:颠覆传统虚拟化的轻量级革命
linux·运维·ubuntu·docker·容器
抓饼先生2 小时前
Linux control group笔记
linux·笔记·bash
挺6的还3 小时前
25.线程概念和控制(二)
linux
您的通讯录好友3 小时前
conda环境导出
linux·windows·conda
代码AC不AC4 小时前
【Linux】vim工具篇
linux·vim·工具详解
码农hbk4 小时前
Linux signal 图文详解(三)信号处理
linux·信号处理
bug攻城狮4 小时前
Skopeo 工具介绍与 CentOS 7 安装指南
linux·运维·centos
宇宙第一小趴菜4 小时前
08 修改自己的Centos的软件源
linux·运维·centos