当前位置: 首页 > 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.dtcms.com/a/323618.html

相关文章:

  • 101-基于Python的个性化音乐推荐系统
  • 码上爬第三题【协程+浏览器调试检测】
  • 本文章分享一个本地录音和实时传输录音给app的功能(杰理)
  • [GPU]什么是“硬件TL”在UnityURP中的体现
  • 疏老师-python训练营-Day40训练和测试的规范写法
  • 并发编程基础:继承Thread vs 实现Runnable - 深入解析与最佳实践
  • Tob大客户销售面试经验
  • 华为交换机进阶功能和场景化配置
  • 最长回文子串(马拉车/Manacher‘s )算法
  • P1053 [NOIP 2005 提高组] 篝火晚会
  • 【C/C++】详解内存对齐问题,C语言内存对齐整理
  • vulhub-Beelzebub靶机
  • 计算网络相关知识
  • 第15届蓝桥杯Scratch图形化省赛初级组2024年8月24日真题
  • 模型微调与RAG在问答系统中的对比分析
  • [激光原理与应用-205]:光学器件 - LD与DFB的比较
  • leetcode 11. 盛最多水的容器 -java
  • Kubernetes CronJob bug解决
  • B站小波变换视频笔记
  • 原创邮件合并Python工具使用说明(附源码)
  • python---变量作用域
  • 零拷贝技术:提升传统I/O的性能
  • 【C++】string 的特性和使用
  • 欢迎走进《励曼旋耕》
  • LintCode第547题-两数组的交集
  • leetcode 49. 字母异位词分组 - java
  • [激光原理与应用-202]:光学器件 - 增益晶体 - Nd:YVO₄增益晶体的制造过程与使用过程
  • vite面试题及详细答案120题(61-90)
  • 简单聊聊PowerShell
  • Effective C++ 条款32:确定你的public继承塑模出 is-a 关系