当前位置: 首页 > news >正文

【学习笔记】非异步安全函数(禁止在信号处理中调用)

非异步安全函数(禁止在信号处理中调用)

一、测试

在信号处理函数(Signal Handler)中,只有异步信号安全函数(async-signal-safe functions) 可以安全调用。这类函数的特点是:不使用全局状态、不依赖内部锁、不调用其他非安全函数,且能被信号中断后安全恢复。

非异步安全函数(禁止在信号处理中调用)

以下是常见的非异步安全函数分类及示例(覆盖大部分常用函数):

1. 内存分配 / 释放函数

这类函数依赖全局堆管理结构和内部锁,信号处理中调用可能导致堆损坏或死锁。

  • mallocfreerealloccalloc
  • posix_memalignaligned_alloc
2. 标准 I/O 函数

标准 I/O 库(stdio.h)函数使用全局缓冲区和锁,信号中断可能导致缓冲区状态不一致。

  • 输入输出:printffprintfsprintfsnprintfvprintfvfprintfvsprintfvsnprintf
  • 文件操作:fopenfclosefreadfwritefseekfflushfgetsfputs
  • 其他:perror(内部调用strerrorfprintf)、fflush
3. 字符串 / 字符处理函数(依赖静态缓冲区)

这类函数使用静态缓冲区存储结果,信号中断可能导致缓冲区内容被覆盖。

  • strtok(使用静态缓冲区存储分割状态)
  • strerror(部分实现使用静态缓冲区存储错误信息)
  • ctimeasctime(使用静态缓冲区存储时间字符串)
  • getpwuidgetpwnam(部分实现使用静态缓冲区存储用户信息)
  • getgrgidgetgrnam(部分实现使用静态缓冲区存储组信息)
4. 线程 / 同步函数

线程相关函数依赖全局锁或线程私有数据,信号处理中调用可能导致死锁。

  • 互斥锁:pthread_mutex_lockpthread_mutex_unlockpthread_mutex_trylock
  • 条件变量:pthread_cond_waitpthread_cond_signalpthread_cond_broadcast
  • 线程管理:pthread_createpthread_joinpthread_cancel
  • 线程私有数据:pthread_getspecificpthread_setspecific
5. 环境变量 / 全局状态函数

这类函数访问或修改全局状态(如环境变量、locale),信号中断可能导致状态不一致。

  • 环境变量:getenvsetenvunsetenvputenv
  • 区域设置:setlocale
  • 进程信息:getuidgetgid(部分实现可能安全,但建议避免)、getpid(通常安全,但 POSIX 未明确)
6. 其他非安全函数
  • 时间函数:localtimegmtime(使用静态缓冲区存储时间结构)
  • 信号相关:signal(非可重入,建议用sigaction替代)
  • 系统调用包装:system(内部创建子进程并调用 shell,依赖全局状态)

为什么这些函数不安全?

非异步安全函数通常存在以下问题:

  1. 使用全局锁:如mallocprintf内部有全局锁,若信号处理函数在主程序持有锁时调用,会导致死锁。
  2. 依赖静态缓冲区:如strtokctime,信号中断可能导致缓冲区数据被覆盖,主程序恢复后读取错误数据。
  3. 修改全局状态:如setenvsetlocale,信号处理中修改全局状态可能导致主程序逻辑混乱。

安全替代方案

信号处理函数中如需完成复杂操作,应仅通过异步安全函数做最小化处理(如设置volatile sig_atomic_t标志),再由主程序轮询标志并执行非安全操作。

常见的异步安全函数包括:write_exitsigprocmaskpthread_sigmaskgetpidgetppid等(完整列表可参考 POSIX 标准man 7 signal-safety)。

总结:信号处理函数中严禁调用上述非异步安全函数,核心原则是 “仅执行最小化、无状态操作”,避免依赖全局资源或锁机制。

举例子

在定时器每秒触发信号的场景下,安全通知线程执行操作的核心是:避免在信号处理函数中直接调用非异步安全接口,而是通过 “信号处理函数→安全通信机制→线程” 的间接方式传递通知。

利用管道(pipe)作为信号和线程之间的安全通信桥梁(write 是异步安全函数),线程通过监听管道数据触发操作。

实现步骤:
  1. 创建管道:用于信号处理函数和工作线程的通信。
  2. 信号处理函数:收到信号后,向管道写 1 字节数据(仅调用 write,异步安全)。
  3. 工作线程:阻塞在管道读端,读取到数据后执行每秒操作。
http://www.dtcms.com/a/353462.html

相关文章:

  • 雷卯针对香橙派Orange Pi 4开发板防雷防静电方案
  • 【Golang】 项目启动方法
  • Android12 user版本默认开启adb调试
  • centos7安装java mysql redis nginx
  • docker 所有常用命令,配上思维导图,加图表显示
  • 713 乘积小于k的子数组
  • Mysql数据挂载
  • Leetcode+Java+动态规划IV
  • electron离线开发环境变量ELECTRON_OVERRIDE_DIST_PATH
  • [MT6835] MT6835开启secureboot导致写入分区提示Security deny for [customer].
  • 【图像算法 - 25】基于深度学习 YOLOv11 与 OpenCV 实现人员跌倒识别系统(人体姿态估计版本)
  • 达梦数据库配置文件-COMPATIBLE_MODE
  • LangChain4j入门一:LangChain4j简介及核心概念
  • 路由基础(一):IP地址规划
  • 基于单片机空调温度控制测温ds18b20系统Proteus仿真(含全部资料)
  • React 组件命名规范:为什么必须大写首字母蛊傲
  • HarmonyOS安全开发实战:一套好用的数据加密方案
  • SQL Server 批量插入脚本
  • 中資券商櫃台系統搭建與開發技術分析
  • AI 大模型 “幻觉” 难题:为何会 “一本正经地说错话”,如何让它更靠谱?
  • 基于Cursor AI IDE的Vue3留言板系统实战:从零搭建到智能优化全流程
  • java数据类型获取长度方式总结
  • 【C++】C++11新特性第一弹(列表初始化、新式声明、范围for和STL中的变化)
  • Flutter 开发技巧 AI 快速构建 json_annotation model 的提示词
  • 使用git上传项目的步骤
  • 煤矸石检测数据集VOC+YOLO格式3090张2类别
  • This method can cause UI unresponsiveness if invoked on the main thread.
  • week5-[字符数组]数和
  • 【技巧】PostgreSQL自动转换类型 int转bool 转int
  • 苍穹外卖项目实战(日记十一)-记录实战教程及问题的解决方法-(day3-3)完善菜品分页查询功能