这是一个在 POSIX 标准中定义的函数,用于查询一个信号集(signal set)中是否包含特定的信号。

(图片来源网络,侵删)
函数简介
sigismember 函数的作用是检查一个给定的信号是否在一个信号集中。
函数原型:
#include <signal.h> int sigismember(const sigset_t *set, int signum);
参数:
set: 指向信号集的指针,这个信号集是你想要查询的目标。signum: 你想要查询的信号编号。SIGINT(2),SIGSEGV(11),SIGUSR1(10) 等。
返回值:

(图片来源网络,侵删)
- 1: 如果信号
signum存在于信号集set中。 - 0: 如果信号
signum不存在于信号集set中。 - -1: 发生错误(
signum是一个无效的信号编号)。errno会被设置为EINVAL。
为什么需要 sigismember?信号集是什么?
在 C 语言中,我们不能直接操作一个 sigset_t 类型的变量,因为它通常是一个不透明的结构体(其内部实现由编译器和操作系统决定),我们只能通过一组专门的函数来操作它。
信号集主要用于:
- 信号掩码: 每个进程都有一个信号掩码,它决定了哪些信号当前被“阻塞”(block),即暂时无法被进程接收,当进程处理完某个任务后,可以检查其信号掩码,看看哪些信号被阻塞了。
sigwaitinfo和sigtimedwait: 这些函数会等待一个信号集中的任意一个信号变为可用(即未被阻塞且未被忽略)。sigismember可以用来检查哪些信号在等待的集合中。sigpending: 这个函数可以获取当前被阻塞但尚未被传递(pending)给进程的信号集。sigismember就可以用来遍历这个 pending 集合,查看哪些信号正在等待被处理。
重要提示: sigset_t 是一个位集合(bit set),每个信号在集合中对应一个 bit。1 表示“包含该信号”,0 表示“不包含该信号”。
如何使用 sigismember?(完整示例)
下面是一个完整的示例程序,演示了如何创建一个信号集、向其中添加信号,然后使用 sigismember 来检查信号是否存在。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h> // for sleep()
// 这是一个辅助函数,用于打印信号集的内容
void print_sigset(const sigset_t *set) {
printf("当前信号集内容: ");
for (int i = 1; i < NSIG; i++) { // NSIG 是信号总数的宏定义
if (sigismember(set, i)) {
printf("%s ", strsignal(i)); // strsignal 将信号编号转换为可读字符串
}
}
printf("\n");
}
int main() {
sigset_t set; // 声明一个信号集变量
// 1. 初始化信号集(清空,所有位都设为0)
sigemptyset(&set);
printf("1. 初始化信号集后:\n");
print_sigset(&set);
// 2. 向信号集中添加 SIGINT (Ctrl+C) 和 SIGUSR1
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1);
printf("\n2. 添加 SIGINT 和 SIGUSR1 后:\n");
print_sigset(&set);
// 3. 使用 sigismember 进行查询
printf("\n3. 查询特定信号:\n");
if (sigismember(&set, SIGINT)) {
printf(" - SIGINT 在信号集中,\n");
} else {
printf(" - SIGINT 不在信号集中,\n");
}
if (sigismember(&set, SIGUSR2)) { // SIGUSR2 不在集合中
printf(" - SIGUSR2 在信号集中,\n");
} else {
printf(" - SIGUSR2 不在信号集中,\n");
}
// 4. 从信号集中移除 SIGINT
sigdelset(&set, SIGINT);
printf("\n4. 移除 SIGINT 后:\n");
print_sigset(&set);
// 5. 再次查询 SIGINT
printf("\n5. 再次查询 SIGINT:\n");
if (sigismember(&set, SIGINT)) {
printf(" - SIGINT 在信号集中,\n");
} else {
printf(" - SIGINT 不在信号集中,\n");
}
// 6. 测试一个无效信号
printf("\n6. 测试一个无效信号 (SIGUNUSED, 通常为0):\n");
int result = sigismember(&set, 0); // 信号编号必须大于0
if (result == -1) {
perror("sigismember 失败");
printf(" 错误: 信号编号无效,\n");
} else {
printf(" (这个查询不应该发生,因为信号0是无效的)\n");
}
return 0;
}
编译和运行:
gcc -o sigismember_example sigismember_example.c ./sigismember_example
预期输出:
初始化信号集后:
2. 添加 SIGINT 和 SIGUSR1 后: SIGINT SIGUSR1
3. 查询特定信号:
- SIGINT 在信号集中。
- SIGUSR2 不在信号集中。
4. 移除 SIGINT 后: SIGUSR1
5. 再次查询 SIGINT:
- SIGINT 不在信号集中。
6. 测试一个无效信号 (SIGUNUSED, 通常为0):
sigismember 失败: Invalid argument
错误: 信号编号无效。
相关函数
sigismember 是一组操作信号集的函数之一,它们通常配合使用:
| 函数名 | 功能 |
|---|---|
sigemptyset(sigset_t *set) |
初始化信号集,将其清空(所有信号都不在集合中)。 |
sigfillset(sigset_t *set) |
初始化信号集,将其填满(所有信号都在集合中)。 |
sigaddset(sigset_t *set, int signum) |
将 signum 信号添加到信号集 set 中。 |
sigdelset(sigset_t *set, int signum) |
从信号集 set 中移除 signum 信号。 |
sigismember(const sigset_t *set, int signum) |
查询 signum 信号是否在信号集 set 中。 |
sigprocmask(int how, const sigset_t *set, sigset_t *oldset) |
修改当前进程的信号掩码。how 可以是 SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK。 |
sigpending(sigset_t *set) |
获取当前被阻塞且处于 pending 状态的信号集。 |
实际应用场景
sigismember 最常见的用途是在信号处理函数中,或者在与信号管理相关的代码中,用来检查信号集的状态。
场景:检查哪些信号被阻塞
#include <signal.h>
#include <stdio.h>
void print_blocked_signals() {
sigset_t current_mask;
// 获取当前进程的信号掩码(即被阻塞的信号集)
if (sigprocmask(SIG_BLOCK, NULL, ¤t_mask) == -1) {
perror("sigprocmask");
return;
}
printf("当前被阻塞的信号有:\n");
for (int i = 1; i < NSIG; i++) {
if (sigismember(¤t_mask, i)) {
printf(" - %s\n", strsignal(i));
}
}
}
int main() {
// ... 假设这里我们阻塞了 SIGINT 和 SIGTERM ...
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_BLOCK, &mask, NULL);
print_blocked_signals();
return 0;
}
sigismember 是一个简单但非常重要的函数,它是操作 POSIX 信号集的核心工具之一,它提供了查询信号集内容的唯一方式,是进行高级信号管理(如自定义信号处理逻辑、实现异步事件管理等)的基础,它只负责查询,不负责修改信号集,修改信号集需要使用 sigaddset, sigdelset, sigprocmask 等函数。
