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

掌握Linux信号集操作技巧

在 Linux 系统编程中,信号集(signal set) 是一组信号的集合,用于管理进程对信号的响应。信号集操作函数(如 sigemptysetsigfillsetsigaddset 等)允许程序员初始化、填充、添加、删除和检查信号集,从而实现对信号的精细控制。


目录

一、信号集数据类型 sigset_t

使用规则:

二、信号集操作函数

1. sigemptyset - 清空信号集

示例代码:

2. sigfillset - 填充信号集

示例代码:

3. sigaddset - 向信号集中添加信号

示例代码:

4. sigdelset - 从信号集中删除信号

示例代码:

5. sigismember - 检查信号是否在信号集中

示例代码:

三、信号集与 sigprocmask 的结合使用

sigprocmask 函数原型:

示例代码:阻塞和解除阻塞信号

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

五、课后练习建议


一、信号集数据类型 sigset_t

sigset_t 是 Linux 中用于表示信号集的数据类型。它本质上是一个位掩码(bitmask),每个位对应一个信号。例如,第 2 位对应 SIGINT(信号编号 2),第 9 位对应 SIGKILL(信号编号 9)。

使用规则:

  1. 必须初始化:在使用 sigset_t 之前,必须调用 sigemptyset 或 sigfillset 初始化。
  2. 避免直接操作:不能直接对 sigset_t 进行位操作,必须通过标准函数操作。

二、信号集操作函数

1. sigemptyset - 清空信号集

#include <signal.h>
int sigemptyset(sigset_t *set);
  • 功能:将信号集 set 初始化为空集(所有位清零)。
  • 返回值:成功返回 0,失败返回 -1(通常不会失败)。
示例代码:
#include <signal.h>
#include <stdio.h>int main() {sigset_t set;if (sigemptyset(&set) == -1) {perror("sigemptyset");return 1;}printf("Signal set is empty.\n");return 0;
}

2. sigfillset - 填充信号集

#include <signal.h>
int sigfillset(sigset_t *set);
  • 功能:将信号集 set 初始化为包含所有信号(所有位置 1)。
  • 返回值:成功返回 0,失败返回 -1。
示例代码:
#include <signal.h>
#include <stdio.h>int main() {sigset_t set;if (sigfillset(&set) == -1) {perror("sigfillset");return 1;}printf("All signals are added to the set.\n");return 0;
}

3. sigaddset - 向信号集中添加信号

#include <signal.h>
int sigaddset(sigset_t *set, int signum);
  • 功能:将信号 signum 添加到信号集 set 中。
  • 返回值:成功返回 0,失败返回 -1(如信号编号无效)。
示例代码:
#include <signal.h>
#include <stdio.h>int main() {sigset_t set;if (sigemptyset(&set) == -1) {perror("sigemptyset");return 1;}if (sigaddset(&set, SIGINT) == -1) {perror("sigaddset");return 1;}printf("SIGINT added to the signal set.\n");return 0;
}

4. sigdelset - 从信号集中删除信号

#include <signal.h>
int sigdelset(sigset_t *set, int signum);
  • 功能:将信号 signum 从信号集 set 中删除。
  • 返回值:成功返回 0,失败返回 -1(如信号编号无效)。
示例代码:
#include <signal.h>
#include <stdio.h>int main() {sigset_t set;if (sigfillset(&set) == -1) {perror("sigfillset");return 1;}if (sigdelset(&set, SIGINT) == -1) {perror("sigdelset");return 1;}printf("SIGINT removed from the signal set.\n");return 0;
}

5. sigismember - 检查信号是否在信号集中

#include <signal.h>
int sigismember(const sigset_t *set, int signum);
  • 功能:检查信号 signum 是否在信号集 set 中。
  • 返回值
    • 1:信号在集合中
    • 0:信号不在集合中
    • -1:失败(如集合未初始化)
示例代码:
#include <signal.h>
#include <stdio.h>int main() {sigset_t set;if (sigemptyset(&set) == -1) {perror("sigemptyset");return 1;}if (sigaddset(&set, SIGINT) == -1) {perror("sigaddset");return 1;}if (sigismember(&set, SIGINT)) {printf("SIGINT is in the set.\n");} else {printf("SIGINT is not in the set.\n");}return 0;
}

三、信号集与 sigprocmask 的结合使用

信号集的一个核心用途是通过 sigprocmask 函数修改进程的信号屏蔽字(blocked signal mask),从而控制哪些信号被阻塞或允许传递。

sigprocmask 函数原型:

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • how:操作方式
    • SIG_BLOCK:将 set 中的信号添加到当前屏蔽字
    • SIG_UNBLOCK:从当前屏蔽字中移除 set 中的信号
    • SIG_SETMASK:将当前屏蔽字设置为 set
  • set:输入的信号集
  • oldset:保存旧的信号屏蔽字

示例代码:阻塞和解除阻塞信号

#include <signal.h>
#include <stdio.h>
#include <unistd.h>void handle_sigint(int signo) {printf("Caught SIGINT\n");
}int main() {struct sigaction sa;sigset_t new_mask, old_mask;// 设置 SIGINT 处理函数sa.sa_handler = handle_sigint;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;if (sigaction(SIGINT, &sa, NULL) == -1) {perror("sigaction");return 1;}// 阻塞 SIGINTsigemptyset(&new_mask);sigaddset(&new_mask, SIGINT);if (sigprocmask(SIG_BLOCK, &new_mask, &old_mask) == -1) {perror("sigprocmask");return 1;}printf("SIGINT is blocked. Press Ctrl+C...\n");sleep(5);  // 在这期间按 Ctrl+C 不会触发处理函数// 解除阻塞if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {perror("sigprocmask");return 1;}printf("SIGINT is unblocked. Press Ctrl+C again...\n");pause();  // 现在按 Ctrl+C 会触发处理函数return 0;
}

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

信号集操作(sigemptyset, sigfillset, sigaddset等)
│
├── sigset_t 类型
│   ├── 位掩码表示信号集合
│   └── 必须初始化后才能使用
│
├── sigemptyset()
│   ├── 功能:清空信号集
│   └── 示例:初始化空集
│
├── sigfillset()
│   ├── 功能:填充所有信号
│   └── 示例:包含所有信号
│
├── sigaddset()
│   ├── 功能:添加指定信号
│   └── 示例:添加 SIGINT
│
├── sigdelset()
│   ├── 功能:删除指定信号
│   └── 示例:删除 SIGINT
│
├── sigismember()
│   ├── 功能:检查信号是否在集合中
│   └── 示例:判断 SIGINT 是否存在
│
└── sigprocmask()├── 功能:修改进程的信号屏蔽字├── how 参数:SIG_BLOCK/SIG_UNBLOCK/SIG_SETMASK└── 示例:阻塞和解除阻塞信号

五、课后练习建议

  1. 编写程序验证信号集操作函数的行为

    • 使用 sigismember 检查不同信号是否在集合理论。
    • 尝试添加和删除多个信号,观察结果。
  2. 实现信号屏蔽与解除屏蔽

    • 使用 sigprocmask 阻塞 SIGINT 和 SIGTERM,然后解除阻塞。
    • 在解除阻塞后测试信号是否能被正常捕获。
  3. 结合 sigaction 和信号集实现复杂逻辑

    • 在信号处理函数中临时阻塞其他信号,避免竞态条件。
  4. 探索错误处理

    • 在信号集操作失败时(如无效信号编号),使用 perror 或 strerror(errno) 分析原因。
  5. 多线程环境下的信号集操作

    • 使用 pthread_sigmask 替代 sigprocmask,了解线程级的信号屏蔽。
gcc your_signal_set_program.c -o your_signal_set_program
./your_signal_set_program
kill -<signal_number> <PID>
http://www.dtcms.com/a/269414.html

相关文章:

  • 人工智能-基础篇-25-认识一下LLM开发应用框架--LangChain
  • RAGflow图像解析与向量化分析
  • Vue 2现代模式打包:双包架构下的性能突围战
  • 【芯片测试篇】:93K测试机I2C的设置和调试
  • 计算机网络:(八)网络层(中)IP层转发分组的过程与网际控制报文协议 ICMP
  • 【排序】插入排序
  • 深入了解linux系统—— System V之消息队列和信号量
  • Flask 解决 JSON 返回中文乱码问题方案
  • Bright Data MCP+Trae :快速构建电商导购助手垂直智能体
  • MySQL Galera Cluster部署
  • 算法化资本——智能投顾技术重构金融生态的深度解析
  • 【UE5】虚幻引擎的运行逻辑
  • 【操作系统】进程(二)内存管理、通信
  • 【喜报】第三届BDDM 会议成功申请 IEEE 冠名,并获得 IEEE 北京分会赞助!
  • 佰力博科技与您探讨电晕极化和油浴极化有什么区别?
  • maven 发布到中央仓库之持续集成-03
  • 当Powerbi遇到quickbi,性能优化方式对比
  • Unity实用技能-背景自适应文本
  • Docker部署QAnything2.0并接入大模型
  • 基于极大似然估计的Gm-APD信号提取算法2025.7.8
  • 技术演进中的开发沉思-28 MFC系列:关于C++
  • 界面控件Telerik UI for WinForms 2025 Q2亮点 - 支持.NET 10 Preview
  • AIGC与影视制作:技术革命、产业重构与未来图景
  • XCKU060‑2FFVA1156I Xilinx FPGA AMD Kintex UltraScale
  • 文献学习|全面绘制和建模水稻调控组景观揭示了复杂性状背后的调控架构。
  • django-ckeditor配置html5video实现视频上传与播放
  • 基于Hadoop的用户购物行为可视化分析系统设计与实现
  • stm32 H7 ADC DMA采集
  • 240.搜索二维矩阵Ⅱ
  • c++-引用(包括完美转发,移动构造,万能引用)