当进程捕捉到信号后,就直接递交给信号处理函数来进行处理,这就是递达状态
执行信号的处理动作称之为信号递达Delivery,信号从产生到递达之间的状态,称为信号未决Pending(前提:进程必须先阻塞某一个信号,信号发生的时候,进程不立刻去执行信号处理函数,而是处于阻塞的状态,这样的状态称之为未决状态)
进程可以选择阻塞Block某个信号;
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作;
注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作
#include
int sigemptyset(sigset_t *set);
将64bit清零
int sigfillset(sigset_t *set);
将64bit都变为1
int sigaddset(sigset_t *set, int signum);
信号对应的位变为1
int sigdelset(sigset_t *set, int signum);
信号对应的位变为0
int sigismember(const sigset_t *set, int signum);
检测信号对应的位是0还是1
#include
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数:
how:改变方式:如何去改变进程中的信号屏蔽字
set:准备的信号集,将信号集按照号所指定的方式改变到进程当中
oldset:返回进程中在改变之前的屏蔽字的状态
返回值:若成功则为0,若出错则为-1
(1)如果oldset是非空指针,则读取进程的当前信号屏蔽字通过oldset参数传出;
(2)如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。
(3)如果oldset和set都是非空指针,则先将原来的信号屏蔽字备份到oldset里,然后根据set和how参数更改信号更改信号屏蔽字。
eg:P19signal.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do \
{ \
perror(m);
exit(EXIT_FAILURE);
} while(0)
void handle(int sig);
void printsigset(sigset_t *set)
{
int i;
for (i = 1; i < NSIG; ++i)//NSIG表示信号的最大值:为64
{
if (sigismember(set, i))//检测对应的信号是否在集合中,若在输出1,不在输出0
putchar('1');
else
putchar('0');
}
printf("\n");
}
void
int main(int argc, char *argv[])
{
sigset_t pset;
if (signal(SIGINT, handle) == SIG_ERR)
ERR_EXIT("signal error");
for(;;)
{
//man sigpending
//sigpending:获取进程中未决的信号集保存到pset
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return 0;
}
void handle(int sig)
{
printf("recv a sig=%d\n", sig);
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do \
{ \
perror(m);
exit(EXIT_FAILURE);
} while(0)
void handle(int sig);
void printsigset(sigset_t *set)
{
int i;
for (i = 1; i < NSIG; ++i)//NSIG表示信号的最大值:为64
{
if (sigismember(set, i))//检测对应的信号是否在集合中,若在输出1,不在输出0
putchar('1');
else
putchar('0');
}
printf("\n");
}
void
int main(int argc, char *argv[])
{
sigset_t pset;
sigset_t bset;
sigemptyset(&bset);
//增加一个阻塞的信号
sigaddset(&bset, SIGINT);
if (signal(SIGINT, handle) == SIG_ERR)
ERR_EXIT("signal error");
//改变进程中的信号屏蔽字
sigprocmask(SIG_BLOCK, &bset, NULL);
for(;;)
{
//man sigpending
//sigpending:获取进程中未决的信号集保存到pset
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return 0;
}
void handle(int sig)
{
printf("recv a sig=%d\n", sig);
}
按下ctrl c,不会递达了,因为进程中的信号屏蔽字已被sigprocmask函数更改,SIG_BLOCK表示将SIGINT对应的位,置1了,所以即使信号到了,也把信号阻塞住了,处于未决状态
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) \
do \
{ \
perror(m);
exit(EXIT_FAILURE);
} while(0)
void handle(int sig);
void printsigset(sigset_t *set)
{
int i;
for (i = 1; i < NSIG; ++i)//NSIG表示信号的最大值:为64
{
if (sigismember(set, i))//检测对应的信号是否在集合中,若在输出1,不在输出0
putchar('1');
else
putchar('0');
}
printf("\n");
}
void
int main(int argc, char *argv[])
{
sigset_t pset;
sigset_t bset;
sigemptyset(&bset);
//增加一个阻塞的信号
sigaddset(&bset, SIGINT);
if (signal(SIGINT, handle) == SIG_ERR)
ERR_EXIT("signal error");
if (signal(SIGQUIT, handle) == SIG_ERR)
ERR_EXIT("signal error");
//改变进程中的信号屏蔽字
sigprocmask(SIG_BLOCK, &bset, NULL);
for(;;)
{
//man sigpending
//sigpending:获取进程中未决的信号集保存到pset
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return 0;
}
void handle(int sig)
{
if (sig == SIGINT)
printf("recv a sig=%d\n", sig);
else if (sig == SIGQUIT)
{
sigset_t uset;
sigemptyset(&uset);
sigaddset(&uset, SIGINT);
//解除对SIGINT信号的阻塞
sigprocmask(SIG_UNBLOCK, &uset, NULL);
}
}
测试:
当按下ctrl \后,解除阻塞,处于未决状态的信号就会被递达,就算多次按下ctrl c,只会有一个未决的状态,因为他是不可靠信号,不支持排队,产生这么多的2号SIGINT信号,只会被保留一个
Makefile
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01sigstatus
all:$(BIN)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o $(BIN)