当前位置: 首页 > 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()设置的定时器
  • 默认行为:终止进程

定时器类型

定时器类型计时方式精度
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.xdnf.cn/news/1268191.html

相关文章:

  • Android 锁屏图标的大小修改
  • 线上排查问题的一般流程是怎么样的?
  • [激光原理与应用-207]:光学器件 - 光纤种子源激光器常用元器件
  • python---类型别名
  • 新手小白使用jQuery在实际开发中常用到的经验
  • ABP VNext + Akka.NET:高并发处理与分布式计算
  • 从 AI 到实时视频通道:基于模块化架构的低延迟直播全链路实践
  • Vuex与Pinia对比,以及技术选型
  • 《C++进阶之继承多态》【普通类/模板类的继承 + 父类子类的转换 + 继承的作用域 + 子类的默认成员函数】
  • 10.final, finally, finalize的区别
  • 【自动化运维神器Ansible】playbook自动化部署Nginx案例解析:助力从零构建高效Web服务
  • 2025 大语言模型系统学习路线:从基础到部署与优化的全方位指南(含权威资源与项目实战)
  • 4深度学习Pytorch-神经网络--损失函数(sigmoid、Tanh、ReLU、LReLu、softmax)
  • IDEA快捷键壁纸分享
  • 光伏面板损伤检出率↑91%!陌讯多模态识别算法在无人机巡检的落地实践
  • AI 破解数据质量难题:从混乱到可信的智能进化之路
  • 计算机网络1-6:计算机网络体系结构
  • webwork的学习
  • 非常简单!从零学习如何免费制作一个lofi视频
  • 香橙派 RK3588 部署千问大模型 Qwen2-VL-2B 推理视频
  • 2025华数杯数学建模C题:可调控生物节律LED光源全解析
  • 2025华数杯B题一等奖方案:网络切片无线资源管理全解析(附Python/MATLAB代码)
  • 机器学习(西瓜书)学习——绪论
  • LeetCode 面试经典 150_数组/字符串_分发糖果(15_135_C++_困难)(贪心算法)
  • 【Redis7.x】docker配置主从+sentinel监控遇到的问题与解决
  • GPT-5:数字大脑的进化史
  • 1393. 与7无关的数?
  • 【Linux】Tomcat
  • 八、Linux Shell 脚本:变量与字符串
  • jupyter服务器创建账户加映射对外账户地址