目录
1 信号集概念
2 sigemptyset、sigfillset初始化信号集
3 sigaddset、sigdelset向信号集中添加/删除信号
4 sigismember函数测试信号是否在信号集中
1 信号集概念
在Linux系统中,信号集(signal set)用于表示一组信号的集合,信号集的使用主要涉及到信号的阻塞与未决状态的管理。很多系统调用都使用到了信号集这种数据类型来作为参数传递,譬如 sigaction()函数、 sigprocmask()函数、 sigpending()函数等。
信号集其实就是 sigset_t 类型数据结构:
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} sigset_t;
宏定义 _SIGSET_NWORDS
:
- 这个宏定义计算了需要多少个
unsigned long int
来表示所有的信号。由于Linux系统支持的信号数量最多为1024(因系统而异),每个unsigned long int
的大小是其位数除以8(即字节数),再乘以sizeof(unsigned long int)
得到每个unsigned long int
的位数。因此,(1024 / (8 * sizeof (unsigned long int)))
计算了总共需要多少个unsigned long int
来存储1024个信号的位图。
sigset_t
结构体:
sigset_t
是一个结构体,它包含一个数组类型是unsigned long int
的__val
的数组,长度由_SIGSET_NWORDS
宏定义决定。
2 sigemptyset、sigfillset初始化信号集
sigemptyset()和 sigfillset()用于初始化信号集。 sigemptyset()初始化信号集,使其不包含任何信号;而sigfillset()函数初始化信号集,使其包含所有信号(包括所有实时信号),函数原型如下:
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
- set: 指向需要进行初始化的信号集变量。
- 返回值: 成功返回 0;失败将返回-1,并设置 errno。
这两个函数通常与 sigaction()
, sigpending()
, sigprocmask()
等函数一起使用,以控制进程对信号的响应和处理。例如,使用 sigfillset()
可以创建一个包含所有信号的信号集,然后通过 sigprocmask()
来阻塞或允许这些信号。
下面是一个简单的使用 sigemptyset()
和 sigfillset()
的示例:
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
int main()
{
sigset_t set, oldset, emptyset;
// 填充信号集
if (sigfillset(&set) == -1) {
perror("Error in sigfillset");
return 1;
}
// 清空信号集
if (sigemptyset(&emptyset) == -1) {
perror("Error in sigemptyset");
return 1;
}
// 阻塞所有信号
if (sigprocmask(SIG_BLOCK, &set, &oldset) == -1) {
perror("Error in sigprocmask - SIG_BLOCK");
return 1;
}
// 打印信号集状态
printf("Current signal set is blocked.\n");
// 恢复信号屏蔽
if (sigprocmask(SIG_SETMASK, &oldset, NULL) == -1) {
perror("Error in sigprocmask - SIG_SETMASK");
return 1;
}
// 打印信号集状态
printf("Original signal set restored.\n");
return 0;
}
运行结果如下:
3 sigaddset、sigdelset向信号集中添加/删除信号
sigaddset()
和 sigdelset()
也是用于操作信号集的函数,允许向信号集中添加或删除特定的信号,函数原型如下:
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
- set: 指向信号集。
- signum: 需要添加/删除的信号。
- 返回值: 成功返回 0;失败将返回-1,并设置 errno。
下面是一个简单的示例,演示如何使用 sigaddset()
和 sigdelset()
:
#include <stdio.h>
#include <signal.h>
#include <errno.h>
int main()
{
sigset_t set;
// 初始化信号集为空
if (sigemptyset(&set) == -1) {
perror("sigemptyset");
return 1;
}
// 添加SIGINT(通常用于处理Ctrl+C中断)到信号集
if (sigaddset(&set, SIGINT) == -1) {
perror("sigaddset");
return 1;
}
// 打印信号集状态,确认SIGINT已添加
if (sigismember(&set, SIGINT)) {
printf("SIGINT is in the signal set.\n");
}
// 从信号集中删除SIGINT
if (sigdelset(&set, SIGINT) == -1) {
perror("sigdelset");
return 1;
}
// 再次打印信号集状态,确认SIGINT已被删除
if (!sigismember(&set, SIGINT)) {
printf("SIGINT is no longer in the signal set.\n");
}
return 0;
}
程序首先使用 sigemptyset()
创建了一个空的信号集,然后使用 sigaddset()
向信号集中添加了 SIGINT
信号,通过 sigismember()
检查 SIGINT
是否成功添加到信号集中,并打印状态信息。接着使用 sigdelset()
删除了 SIGINT
信号,并再次检查信号集状态,确认 SIGINT
已被删除。运行结果乳香
4 sigismember函数测试信号是否在信号集中
使用 sigismember()函数可以测试某一个信号是否在指定的信号集中,函数原型如下所示:
#include <signal.h>
int sigismember(const sigset_t *set, int signum);
- set: 指定信号集。
- signum: 需要进行测试的信号。
- 返回值: 如果信号 signum 在信号集 set 中,则返回 1;如果不在信号集 set 中,则返回 0;失败则返回-1,并设置 errno。
以下是一个使用 sigismember()
的示例代码:
#include <stdio.h>
#include <signal.h>
#include <errno.h>
int main()
{
sigset_t set;
// 初始化信号集,包含所有信号
if (sigfillset(&set) == -1) {
perror("sigfillset");
return 1;
}
// 检查SIGINT是否在信号集中
if (sigismember(&set, SIGINT)) {
printf("SIGINT is in the signal set.\n");
} else {
printf("SIGINT is not in the signal set.\n");
}
return 0;
}
程序首先使用 sigfillset()
填充信号集 set
,使其包含所有可能的信号。然后使用 sigismember()
检查 SIGINT
是否是信号集的成员,并打印相应的信息。运行结果如下: