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

常用信号深度解析(SIGINT、SIGPIPE、SIGALRM、SIGTERM等)

信号全景图概览

信号名称默认行为触发场景关键特性
SIGINT终止进程2键盘Ctrl+C可捕获,优雅终止
SIGPIPE终止进程13向断开的管道/套接字写入网络编程必处理
SIGALRM终止进程14定时器到期时间驱动编程核心
SIGTERM终止进程15kill命令默认信号优雅关闭首选
SIGKILL终止进程9强制终止命令不可捕获/忽略
SIGCHLD忽略17子进程状态改变进程管理关键

SIGINT:交互中断信号

核心特性

  • 信号值:2
  • 触发方式:键盘Ctrl+C
  • 默认行为:终止进程

详细解析

// 典型捕获处理
void sigint_handler(int sig) {printf("\n收到SIGINT,正在保存数据...\n");save_work();      // 保存工作进度cleanup();        // 清理资源exit(EXIT_SUCCESS); // 优雅退出
}int main() {struct sigaction sa;sa.sa_handler = sigint_handler;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;sigaction(SIGINT, &sa, NULL);// 主程序逻辑while(1) {process_data();}
}

应用场景

  1. 命令行工具:允许用户中断长时间操作
  2. 交互式程序:游戏保存进度后退出
  3. 服务进程:开发调试时快速终止

特殊注意

  • 在终端中,Ctrl+C发送SIGINT到整个前台进程组
  • 守护进程通常忽略SIGINT(因脱离终端控制)

SIGPIPE:管道破裂信号

核心特性

  • 信号值:13
  • 触发条件:向已关闭的管道/套接字写入数据
  • 默认行为:终止进程

产生机制

写入进程管道/套接字读取进程关闭读取端写入数据返回EPIPE错误发送SIGPIPE信号写入进程管道/套接字读取进程

正确处理方案

// 方案1:忽略信号(推荐)
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);// 方案2:捕获处理
void pipe_handler(int sig) {// 记录日志,关闭连接等log("管道破裂,连接已断开");close(fd);
}// 检查写入返回值
ssize_t n = write(sockfd, buf, len);
if (n == -1) {if (errno == EPIPE) {// 处理管道破裂reconnect();}
}

应用场景

  1. 网络编程:客户端断开后服务端继续写入
  2. 管道操作producer | consumer中consumer提前退出
  3. 进程通信:无名管道一端关闭后写入

行业实践

  • 所有网络服务程序必须处理SIGPIPE
  • Nginx/Redis等均默认忽略此信号
  • 忽略后write()返回EPIPE错误而非终止进程

SIGALRM:定时器信号

在这里插入图片描述

核心特性

  • 信号值:14
  • 触发源alarm()setitimer()设置的定时器
  • 默认行为:终止进程
  • 信号处理:如果没有设置,则执行默认行为“发起alarm()进程被内核终止”,若定义,则处理定义的信号处理函数

定时器类型

定时器类型计时方式精度
ITIMER_REAL真实时间毫秒级
ITIMER_VIRTUAL进程用户态CPU时间高精度
ITIMER_PROF进程总CPU时间高精度

代码示例

// 单次定时器
alarm(30);  // 30秒后发送SIGALRM// 周期定时器
struct itimerval timer = {.it_interval = {1, 500000},  // 1.5秒间隔.it_value = {0, 100000}       // 100ms后首次触发
};
setitimer(ITIMER_REAL, &timer, NULL);// 定时器处理函数
void alarm_handler(int sig) {printf("定时任务执行\n");update_cache();  // 定期更新缓存
}

应用场景

  1. 超时控制:网络请求超时断开
    alarm(10);  // 设置10秒超时
    recv_data(); // 接收数据
    alarm(0);   // 取消超时
    
  2. 周期任务:定时保存状态/清理资源
  3. 看门狗:监控进程健康状态

注意事项

  • 多个定时器会相互覆盖(最后设置的生效)
  • 实时信号更适合高精度定时需求(SIGRTMIN+)

SIGTERM:终止请求信号

核心特性

  • 信号值:15
  • 触发源kill命令默认信号
  • 默认行为:终止进程

优雅关闭流程

收到SIGTERM
停止接受新请求
完成进行中任务
释放资源
关闭日志
退出进程

处理模板

volatile sig_atomic_t shutdown_flag = 0;void term_handler(int sig) {shutdown_flag = 1;  // 设置优雅关闭标志
}int main() {// 注册信号处理struct sigaction sa;sa.sa_handler = term_handler;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;sigaction(SIGTERM, &sa, NULL);// 主循环while (!shutdown_flag) {process_requests();}// 清理阶段stop_accepting();drain_connections();release_resources();exit(EXIT_SUCCESS);
}

应用场景

  1. 服务关闭:systemd停止服务时发送
  2. 容器编排:Docker/Kubernetes停止容器
  3. 进程管理:优雅终止后台守护进程

行业实践

  • 标准关闭流程:SIGTERM → 等待超时 → SIGKILL
  • Kubernetes默认30秒优雅关闭期
  • 重要数据服务需要实现两阶段关闭(暂停写入→完全停止)

信号处理高级技巧

1. 信号屏蔽与原子操作

// 关键操作期间屏蔽信号
sigset_t mask, oldmask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);sigprocmask(SIG_BLOCK, &mask, &oldmask);
perform_critical_section();  // 不会被SIGTERM中断
sigprocmask(SIG_SETMASK, &oldmask, NULL);

2. 实时信号应用

// 发送带参数的实时信号
union sigval value;
value.sival_int = 42;
sigqueue(pid, SIGRTMIN+3, value);// 接收处理
void rt_handler(int sig, siginfo_t *info, void *ctx) {int data = info->si_value.sival_int;printf("收到数据: %d\n", data);
}

3. 多线程信号处理

// 主线程设置屏蔽
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, NULL);// 专用信号线程
void *signal_thread(void *arg) {sigset_t wait_set;sigemptyset(&wait_set);sigaddset(&wait_set, SIGTERM);int sig;while (1) {sigwait(&wait_set, &sig);handle_signal(sig);}
}

信号安全编程黄金法则

  1. 异步安全原则

    • 信号处理函数中只使用异步信号安全函数
    • 禁止使用:malloc, printf, pthread_mutex_lock等
  2. 标志位通信

    volatile sig_atomic_t flag = 0;  // 唯一安全的全局变量通信
    
  3. 避免重入问题

    • 使用sa_mask屏蔽相关信号
    • 避免修改全局状态
  4. 资源清理

    • 信号处理中只做最低限度操作
    • 复杂清理在主线程中进行
  5. 便携性考虑

    • 始终使用sigaction替代signal
    • 明确设置sa_flags避免平台差异

理解这些常用信号的特性和正确处理方式,是构建健壮、可靠系统软件的基石。每种信号都有其特定应用场景,合理使用可以极大提升程序的容错性和用户体验。

http://www.lryc.cn/news/615639.html

相关文章:

  • Java安全-组件安全
  • 谷歌搜索 sg_ss 逆向分析
  • nginx的安装
  • 智能的本质
  • Linux之shell脚本篇(四)
  • 【工具变量】地市人力资本水平数据集(2003-2023年)
  • 9. 堆和栈有什么区别
  • 健全性测试(Sanity Testing):你软件的快速“体检” ✅(省时避坑,确保核心!)
  • PID学习笔记1
  • 复现论文关于3-RPRU并联机器人运动学建模与参数优化设计
  • QT环境搭建
  • 功能测试中常见的面试题-二
  • 【Python 高频 API 速学 ⑥】
  • 09 【C++ 初阶】C/C++内存管理
  • [激光原理与应用-207]:光学器件 - 光纤种子源激光器常用元器件
  • Linux文件系统基石:透彻理解inode及其核心作用
  • 【高等数学】第八章 向量代数与空间解析几何——第四节 空间直线及其方程
  • 分析报告:基于字节连续匹配技术的KV缓存共享实施可能性及其扩展
  • 【机器学习深度学习】模型选型:如何根据模型的参数算出合适的设备匹配?
  • 202506 电子学会青少年等级考试机器人二级理论综合真题
  • 202506 电子学会青少年等级考试机器人三级器人理论真题
  • openvela之STM32开发板部署
  • LLM表征的提取方式
  • EP06:【DL 第二弹】动态计算图与梯度下降入门
  • UCMT部分复现
  • Chaos Monkey 故障注入工具使用介绍
  • Spring Boot Starter 自动化配置原理深度剖析
  • CentOS7编译安装GCC
  • C++高频知识点(十七)
  • C++ 虚函数、多重继承、虚基类与RTTI的实现成本剖析