一、概述
在另一篇实例说到,进程可以屏蔽它不想接收的信号集。
事实上这些被屏蔽的信号只是阻塞在内核的进程表中,因为他们不能递送给进程,所以状态是未决的(pending)。
利用sigpending函数可以返回这些未决信号集。
int sigpending(sigset_t *set);
二、示例
1.示例中进程屏蔽了SIGUSR1信号,当给进程发送该信号后,它就会被sigpending函数返回,可以尝试先向进程发送SIGUSR2,然后再发送SIGUSR1,再而发送SIGUSR2,观察信号处理函数的变化。
#include <stdio.h> #include <unistd.h> #include <signal.h> void sig_usr(int signo) { sigset_t s_2; if (signo == SIGUSR1) printf("received SIGUSR1\n"); else if (signo == SIGUSR2) printf("received SIGUSR2\n"); else printf("received signal %d\n", signo); sigpending(&s_2); if(sigismember(&s_2, SIGUSR1)) printf("SIGUSR1 pending\n"); } int main(void){ sigset_t s_1; sigemptyset(&s_1); sigaddset(&s_1, SIGUSR1); sigprocmask(SIG_SETMASK, &s_1, NULL); signal(SIGUSR1, sig_usr); signal(SIGUSR2, sig_usr); for (;;) { pause(); } return 0; }
2.现在来修改一下示例1,把信号处理函数改为,当检测到有SIGUSR1被阻塞时,马上释放它(再次调用屏蔽字函数,把信号集设为空集)
#include <stdio.h> #include <unistd.h> #include <signal.h> void sig_usr(int signo) { sigset_t s_2, s_3; if (signo == SIGUSR1) printf("received SIGUSR1\n"); else if (signo == SIGUSR2) printf("received SIGUSR2\n"); else printf("received signal %d\n", signo); sigpending(&s_2); if(sigismember(&s_2, SIGUSR1)){ printf("SIGUSR1 pending, now release it\n"); sigemptyset(&s_3); sigprocmask(SIG_SETMASK, &s_3, NULL); } } int main(void){ sigset_t s_1; sigemptyset(&s_1); sigaddset(&s_1, SIGUSR1); sigprocmask(SIG_SETMASK, &s_1, NULL); signal(SIGUSR1, sig_usr); signal(SIGUSR2, sig_usr); for (;;) { pause(); } return 0; }
测试时,先发送两次SIGUSR1信号,然后发送一次SIGUSR2信号,输出结果是:
received SIGUSR2
SIGUSR1 pending, now release it
received SIGUSR1
可见:
1.信号被释放后进程马上接收到了该信号。
2.尽管已向进程发送了多次SIGUSR1,但是最后的释放,进程只收到一次SIGUSR1信号,这是因为有些信号是不被列队的,如果阻塞该信号,那么尽管发送了多次,最后释放时也只会收到一次,请参考《Unix高级环境编程》第10.13章。