文章目录
  1. 信号集函数
  2. 进程信号掩码
  3. 被挂起的信号
  4. 统一事件源

信号集函数

__sigset_t类型定义如下。

1
2
3
4
5
6
/*
引用方式: #include <bits/sigset.h>
*/
typedef struct{
unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];
}__sigset_t;

__sigset_t实际是一个长整型数组,其中每个元素的每一位表示一个信号。Linux提供了一组函数来设置、修改、删除与查询信号集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
引用方式: #include <signal.h>
sigemptyset: 清空信号集
sigfillset: 在信号集中设置所有信号
sigaddset: 将信号signo添加到信号集中
sigdelset: 将信号signo从信号集中删除
sigismember: 测试signo是否在信号集中
*/
int sigemptyset(__sigset_t * set);

int sigfillset(__sigset_t * set);

int sigaddset(__sigset_t * set, int signo);

int sigdelset(__sigset_t * set, int signo);

int sigismember(const __sigset_t * set, int signo);

进程信号掩码

若要单独设置进程的信号掩码,使用sigprocmask函数(也能查看进程的信号掩码);

1
2
3
4
5
6
7
8
/*
引用方式: #include <signal.h>
how: 指定设置进程信号掩码的方式(详见下表)
set: 指定新的信号掩码
oset: 存放进程原有信号掩码
返回0: 成功 || 返回-1并设置errno: 失败
*/
int sigprocmask(int how, const __sigset_t * set, __sigset_t * oset);

被挂起的信号

若其他进程向本进程发送一个被本进程屏蔽的信号,则操作系统将该信号设置为本进程的一个被挂起的信号。当本进程取消对被挂起信号的屏蔽后,它会立即被本进程接收,使用sigpending函数获得本进程当前被挂起的信号集。

1
2
3
4
5
6
/*
引用方式: #include <signal.h>
set: 存放被挂起的信号集(即使某个信号向进程发送了多次,sigpending也只能反应一次, 相应的信号处理函数也只会触发一次)
返回0: 成功 || 返回-1并设置errno: 失败
*/
int sigpending(__sigset_t * set);

注:编写网络程序时,不能设想新创建的进程/线程具有与父进程完全相同的信号特征;如fork调用产生的子进程将继承父进程的信号掩码,但子进程的挂起信号集为空!

统一事件源

信号作为一种异步事件,使得信号处理函数与网络程序的主循环是两条不同的执行路线。为避免信号在信号处理函数执行过程中被屏蔽太久,一种典型的解决方案是:将信号的主要处理逻辑放到网络程序的主循环中,被触发的信号处理函数只是简单地通知主循环程序接收的信号;主循环程序再根据接收到的信号值执行信号对应的逻辑代码。

信号处理函数通常使用管道将信号通知给主循环,主循环使用I/O复用系统调用进行监听管道读端文件的可读事件。

由于这种处理方式使得信号事件能够和其他I/O事件一样被处理,因此称为统一事件源。