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

Linux信号处理全解析

在 Linux 系统编程中,信号(Signal) 是一种异步通知机制,用于告知进程发生了某种事件。理解常见的信号及其默认行为对于编写健壮的应用程序至关重要。


目录

一、信号的分类与作用

1. SIGHUP(信号编号:1)

2. SIGINT(信号编号:2)

3. SIGQUIT(信号编号:3)

4. SIGILL(信号编号:4)

5. SIGABRT(信号编号:6)

6. SIGFPE(信号编号:8)

7. SIGKILL(信号编号:9)

8. SIGUSR1 和 SIGUSR2(信号编号:10 和 12)

9. SIGSEGV(信号编号:11)

10. SIGPIPE(信号编号:13)

11. SIGALRM(信号编号:14)

12. SIGTERM(信号编号:15)

13. SIGCHLD(信号编号:17)

14. SIGCONT(信号编号:18)

15. SIGSTOP(信号编号:19)

16. SIGTSTP(信号编号:20)

二、信号的处理方式

示例代码:自定义信号处理函数

使用 sigaction() 更精确地设置信号处理函数

三、信号的阻塞与未决

示例代码:演示信号阻塞

四、总结知识点图解(知识树状图)

五、课后练习建议


一、信号的分类与作用

Linux 定义了多种信号,每个信号都有一个编号和默认的行为。下面列出了一些常用的信号及其用途:

1. SIGHUP(信号编号:1)

  • 默认行为:终止
  • 用途:当控制终端关闭或网络连接断开时发送给进程。通常用于通知守护进程重新加载配置文件。

2. SIGINT(信号编号:2)

  • 默认行为:终止
  • 用途:由用户通过键盘输入中断字符(通常是 Ctrl+C)产生,要求进程停止执行。

3. SIGQUIT(信号编号:3)

  • 默认行为:核心转储后终止
  • 用途:类似于 SIGINT,但要求进程生成核心转储文件以便调试。

4. SIGILL(信号编号:4)

  • 默认行为:核心转储后终止
  • 用途:非法指令错误,例如尝试执行无效的操作码。

5. SIGABRT(信号编号:6)

  • 默认行为:核心转储后终止
  • 用途:由调用 abort() 函数触发,用于异常终止程序并生成核心转储文件。

6. SIGFPE(信号编号:8)

  • 默认行为:核心转储后终止
  • 用途:浮点运算错误,如除以零或溢出。

7. SIGKILL(信号编号:9)

  • 默认行为:强制终止
  • 用途:无法被捕获或忽略,用于立即终止进程,通常作为最后手段。

8. SIGUSR1 和 SIGUSR2(信号编号:10 和 12)

  • 默认行为:终止
  • 用途:用户定义的信号,可用于应用程序内部通信或特殊处理逻辑。

9. SIGSEGV(信号编号:11)

  • 默认行为:核心转储后终止
  • 用途:无效内存引用(段错误),常用于调试内存访问问题。

10. SIGPIPE(信号编号:13)

  • 默认行为:终止
  • 用途:写入管道或 socket 连接已关闭时触发。

11. SIGALRM(信号编号:14)

  • 默认行为:终止
  • 用途:由 alarm() 函数设置的定时器超时时触发,常用于实现定时任务。

12. SIGTERM(信号编号:15)

  • 默认行为:终止
  • 用途:请求进程正常终止,可以被捕获和处理,比 SIGKILL 更友好。

13. SIGCHLD(信号编号:17)

  • 默认行为:忽略
  • 用途:子进程状态改变时发送给父进程,用于回收僵尸进程。

14. SIGCONT(信号编号:18)

  • 默认行为:继续执行
  • 用途:如果进程被暂停,则恢复其执行。

15. SIGSTOP(信号编号:19)

  • 默认行为:暂停
  • 用途:不可捕获或忽略,用于暂停进程执行。

16. SIGTSTP(信号编号:20)

  • 默认行为:暂停
  • 用途:类似 SIGSTOP,但可被捕获或忽略,通常由终端输入 Ctrl+Z 触发。

二、信号的处理方式

对于每一个信号,可以采取以下三种处理方式之一:

  1. 默认动作:根据信号类型采取相应操作(如终止进程、忽略信号等)。
  2. 忽略信号:使用 signal() 或 sigaction() 注册忽略处理函数。
  3. 自定义处理函数:为信号指定一个处理函数,当信号到达时会调用该函数。

示例代码:自定义信号处理函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>void handle_signal(int sig) {printf("Caught signal %d\n", sig);
}int main() {// 设置 SIGINT 的处理函数if (signal(SIGINT, handle_signal) == SIG_ERR) {perror("signal");exit(EXIT_FAILURE);}printf("Press Ctrl+C to test...\n");while (1) {pause();  // 挂起等待信号}return 0;
}

使用 sigaction() 更精确地设置信号处理函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>void handle_signal(int sig) {printf("Caught signal %d\n", sig);
}int main() {struct sigaction sa;sa.sa_handler = handle_signal;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;if (sigaction(SIGINT, &sa, NULL) == -1) {perror("sigaction");exit(EXIT_FAILURE);}printf("Press Ctrl+C to test...\n");while (1) {pause();}return 0;
}

三、信号的阻塞与未决

有时候我们需要暂时阻止某些信号的传递,即使信号已经发送也不会立即处理,直到解除阻塞为止。此时这些信号处于“未决”状态。

示例代码:演示信号阻塞

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>void handle_signal(int sig) {printf("Caught signal %d\n", sig);
}int main() {sigset_t newmask, oldmask;// 设置 SIGINT 的处理函数struct sigaction sa;sa.sa_handler = handle_signal;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;sigaction(SIGINT, &sa, NULL);// 阻塞 SIGINTsigemptyset(&newmask);sigaddset(&newmask, SIGINT);if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {perror("sigprocmask");exit(EXIT_FAILURE);}printf("Blocked SIGINT, press Ctrl+C...\n");sleep(10);  // 在这期间按 Ctrl+C 不会触发 handler// 解除阻塞if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {perror("sigprocmask");exit(EXIT_FAILURE);}printf("Unblocked SIGINT\n");pause();  // 现在按 Ctrl+C 会触发 handlerreturn 0;
}

四、总结知识点图解(知识树状图)

常见信号及其用途
│
├── SIGHUP
│   ├── 编号:1
│   └── 用途:通知守护进程重新加载配置
│
├── SIGINT
│   ├── 编号:2
│   └── 用途:用户请求中断(Ctrl+C)
│
├── SIGQUIT
│   ├── 编号:3
│   └── 用途:用户请求退出并生成 core 文件(Ctrl+\)
│
├── SIGILL
│   ├── 编号:4
│   └── 用途:非法指令错误
│
├── SIGABRT
│   ├── 编号:6
│   └── 用途:调用 abort() 时生成 core 文件
│
├── SIGFPE
│   ├── 编号:8
│   └── 用途:浮点运算错误
│
├── SIGKILL
│   ├── 编号:9
│   └── 用途:强制终止进程
│
├── SIGUSR1 / SIGUSR2
│   ├── 编号:10 / 12
│   └── 用途:用户定义信号
│
├── SIGSEGV
│   ├── 编号:11
│   └── 用途:无效内存引用
│
├── SIGALRM
│   ├── 编号:14
│   └── 用途:定时器超时
│
├── SIGTERM
│   ├── 编号:15
│   └── 用途:请求进程正常终止
│
├── SIGCHLD
│   ├── 编号:17
│   └── 用途:子进程状态变化
│
├── SIGCONT
│   ├── 编号:18
│   └── 用途:继续暂停的进程
│
├── SIGSTOP
│   ├── 编号:19
│   └── 用途:暂停进程
│
└── SIGTSTP├── 编号:20└── 用途:终端停止命令(Ctrl+Z)

五、课后练习建议

  1. 编写程序注册不同信号的处理函数,并通过 kill 命令发送信号测试。
  2. 实现一个简单的计时器,使用 alarm() 和 SIGALRM 处理函数实现定时任务。
  3. 修改上面的例子,让程序在接收到 SIGINT 后不退出,而是打印一条消息并继续运行。
  4. 使用 sigaction() 替代 signal(),体验更精细的信号处理控制。
  5. 探索如何使用 sigprocmask() 和 sigsuspend() 实现更复杂的信号同步逻辑。
gcc your_signal_program.c -o your_signal_program
./your_signal_program &
kill -<signal_number> <PID>
http://www.dtcms.com/a/269262.html

相关文章:

  • Qt中的QProcess类
  • 【学习笔记】大数定理,频率与概率,均值与期望的区别
  • MySQL数据表设计 系统的营销功能 优惠券、客户使用优惠券的设计
  • 2025Q2大模型更新汇总(大语言模型篇)
  • Web后端开发-分层解耦
  • 【Java面试】如何保证接口的幂等性?
  • Day06_刷题niuke20250707
  • pythone相关内容一
  • Spring 如何干预 Bean 的生命周期?
  • 洛谷 P5788 【模板】单调栈
  • 龙旗科技社招校招入职测评25年北森笔试测评题库答题攻略
  • 人工智能-基础篇-22-什么是智能体Agent?(具备主动执行和调优的人工智能产物)
  • elementUI vue2 前端表格table数据导出(二)
  • 超光谱相机的原理和应用场景
  • Java后端技术博客汇总文档
  • C语言——编译与链接
  • Dash 代码API文档管理工具 Mac电脑
  • JVM基础01(从入门到八股-黑马篇)
  • 力扣网编程274题:H指数之普通解法(中等)
  • ExcelJS 完全指南:专业级Excel导出解决方案
  • Web前端——css样式(盒子模型)
  • R语言爬虫实战:如何爬取分页链接并批量保存
  • Docker 稳定运行与存储优化全攻略(含可视化指南)
  • 田间杂草分割实例
  • 【PTA数据结构 | C语言版】求数组与整数乘积的最大值
  • OpenWebUI(2)源码学习-后端retrieval检索模块
  • YMS系统开发2-EAP自动化SECS/GEM协议详解
  • python的瑜伽体验课预约系统
  • vue时间轴,antd时间轴,带卡片时间轴
  • Windows 和 Linux 好用网络命令