一、可靠信号与不可靠信号
信号分为可靠信号(1~31)和不可靠信号(34~64)
不可靠信号主要有以下问题:
(1)每次信号处理完之后,就会恢复成默认处理(早期的signal函数,但是在Linux2.6.35.6内核经验证已经不再恢复成默认处理了,也就是说这个问题只限于早期的Linux版本,现已不用考虑)
(2)存在信号丢失的问题,进程收到的信号不做排队处理,相同的信号多次收到时可能会合并成一个。
现在的Linux对信号机制进行了改进,因此,不可靠信号主要是指信号丢失。
以上问题可以自行验证
二、信号处理函数被中断问题
当一个信号到达后,调用处理函数,如果此时有其他类型的信号发生会中断之前的处理函数,等新的信号处理函数执行完成后再回来继续执行之前的函数。
但是,同一个信号会排队阻塞。(如果信号是不可靠信号时,需要注意信号的丢失问题,比如说收到了5个信号,可能只会执行3/4个,原因上面已提到,但那3/4个信号也会进行排队阻塞)
三、信号阻塞
如果不希望在接到信号时中断当前的处理函数,也不希望忽略该信号,而是想延时一段时间再处理这个信号,这种情况可以通过信号阻塞来实现。
示例:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void func(int sig);
int main()
{
// int sigemptyset(sigset_t *set);
// int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int i;
sigset_t set; // 定义信号集
sigemptyset(&set); // 清空信号集
sigaddset(&set,2); // 把信号2加入信号集
sigprocmask(SIG_BLOCK,&set,NULL); // 阻塞信号集
signal(2,func);
signal(15,func);
for(i=0;i<100;i++){
printf("i = %d\n",i);
if(i>20){ // 解除信号集阻塞
sigprocmask(SIG_UNBLOCK,&set,NULL);
}
sleep(1);
}
return 0;
}
void func(int sig)
{
int jj;
printf("signal is %d\n",sig);
for(jj=0;jj<5;jj++){
printf("jj(%d)=%d\n",sig,jj);
sleep(1);
}
}
// void func(int sig)
// {
// sigset_t set; // 定义信号集
// sigemptyset(&set); // 清空信号集
// sigaddset(&set,2); // 把信号2加入信号集
// sigprocmask(SIG_BLOCK,&set,NULL); // 阻塞信号集
// int jj;
// printf("signal is %d\n",sig);
// for(jj=0;jj<5;jj++){
// printf("jj(%d)=%d\n",sig,jj);
// sleep(1);
// }
//
// }
先发送信号15,再发送信号2
结果:
信号的阻塞和忽略信号是不同的,被阻塞的信号也不会影响进程的行为,信号只是暂时被阻止传递。 而进程忽略一个信号时,信号会被传递出去但是会被进程抛弃。
还有这么个概念就是,执行信号的处理动作称为信号递达(Delivery),信号从发生到递达之间的状态,称为信号未决(Pending)。 可以通过信号是否处于信号未决的状态可以知道阻塞信号集中的某个信号是否已经执行了相应的函数,Linux的库函数为(int sigpending(sigset_t *set); 具体用法看手册。
关于信号集的库函数还有:
int sigemptyset(sigset_t *set); // 清空
int sigfillset(sigset_t *set); // 填充所有信号进信号集中
int sigaddset(sigset_t *set, int signum); // 添加某信号
int sigdelset(sigset_t *set, int signum); // 删除某信号
int sigismember(const sigset_t *set, int signum); // 判断某信号是不是在此信号集中
具体用法看手册