- 功能:用来检测或修改信号屏蔽字,或者同时检测和修改信号屏蔽字
- 注意事项(重点):sigprocmask仅为单线程定义,多线程使用另一个函数
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set,sigset_t *restrict oset);
参数:
- 检测信号屏蔽字功能:如果oset是非空指针,进程的当前信号屏蔽字通过oset返回
- 修改信号屏蔽字功能:如果set是一个非空指针, 则参数how指示如何修改当前信号屏蔽字
- 如果set是个空指针,则不改变该进程的信号屏蔽字, how的值也无意义
how取值如下:
SIG_BLOCK(或操作) 该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集
set包含了我们希望阻塞的附加信号
SIG_UNBLOCK 该进程新的信号屏蔽字是其当前信号屏蔽字和set所指向信号集的交集
set包含了我们希望解除阻塞的信号
SIG_SETMASK(赋值操作 ) 该进程新的信号屏蔽是set指向的值 返回值:
- 若成功则为0,若出错则为-1并设置errno
二、sigpending演示案例
- 打印调用该函数的进程信号屏蔽字中的信号名
#include <errno.h> #include<stdio.h> #include<signal.h> void pr_mask(const char *str); int main() { sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGINT); sigprocmask(SIG_SETMASK,&sigset,NULL); pr_mask("I am sigpromask.c"); } void pr_mask(const char *str) { sigset_t sigset; int errno_save; errno_save = errno; /* we can be called by signal handlers */ if (sigprocmask(0, NULL, &sigset) < 0) { perror("sigprocmask error"); } else { printf("%s\n", str); if (sigismember(&sigset, SIGINT)) printf(" SIGINT"); if (sigismember(&sigset, SIGQUIT)) printf(" SIGQUIT"); if (sigismember(&sigset, SIGUSR1)) printf(" SIGUSR1"); if (sigismember(&sigset, SIGALRM)) printf(" SIGALRM"); printf("\n"); } errno = errno_save; }
- 演示结果(程序中信号屏蔽字中设置了SIGINT信号为阻塞信号)
- 功能:返回一个阻塞信号集,信号集中的信号都是阻塞的
#include <signal.h>
int sigpending(sigset_t *set);
- 参数:保存进程的阻塞信号集
- 返回值:若成功则为0,若出错则为-1并设置errno
三、sigprocmask、sigpending综合使用演示案例
#include<stdio.h> #include<signal.h> #include<stdlib.h> static void sig_quit(int); int main(void) { sigset_t newmask, oldmask, pendmask; if (signal(SIGQUIT, sig_quit) == SIG_ERR) perror("can’t catch SIGQUIT"); sigemptyset(&newmask); sigaddset(&newmask, SIGQUIT); //将SIGQUIT信号设置为阻塞的,同时保存旧的信号屏蔽字,此屏蔽字没有SIGQUIT信号 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) perror("SIG_BLOCK error"); sleep(5); if (sigpending(&pendmask) < 0) perror("sigpending error"); if (sigismember(&pendmask, SIGQUIT)) printf("\nSIGQUIT pending\n"); //将旧的信号屏蔽字给该进程,从而解除对SIGQUIT信号的阻塞 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) perror("SIG_SETMASK error"); printf("SIGQUIT unblocked\n"); sleep(5); exit(0); } static void sig_quit(int signo) { printf("caught SIGQUIT\n"); if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) perror("can’t reset SIGQUIT"); }
演示结果
- SIGQUIT信号是键盘输入crrl+\产生的
- 我们在第一次sleep(5)之前输入ctrl+\,然后产生的SIGQUIT信号被设置为阻塞的
- 在sigprocmask(SIG_BLOCK, &newmask, &oldmask)函数中将阻塞的SIGQUIT信号移除了,SIGQUIT信号不在阻塞,从而进程接收到,然后打印caught SIGQUIT,最后再打印SIGQUIT unblocked
- 我们第二次输入了多个ctrl+\,但是SIGQUIT信号接触阻塞后,进程只捕获一个SIGQUIT信号,因此不会对阻塞的信号进行排队
- 程序运行10秒之前,如果有SIGINT信号传进来,就将SIGINT信号屏蔽字,10秒之后取消对SIGINT信号的屏蔽
- 并且每秒都打印一次当前进程的信号屏蔽字
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/types.h>
void handler(int sig)
{
printf("get a sig,num is:%d\n",sig);
}
void print_sig(sigset_t *p)
{
int i = 1;
for(;i < 32;++i){ //打印。循环打印位域,看看是哪一个信号
if(sigismember(p,i)){
printf("1");
}else{
printf("0");
}
}
printf("\n");
}
int main()
{
signal(2,handler); //等待SIGINT信号
sigset_t s,p,o;
sigemptyset(&s);
sigemptyset(&o);
sigaddset(&s,SIGINT);
sigprocmask(SIG_SETMASK,&s,&o); //将SIGINT信号屏蔽
int count = 0;
while(1){
sigemptyset(&p);
sigpending(&p); //获取当前进程的屏蔽字
print_sig(&p); //打印信号屏蔽字
sleep(1); //休眠1秒
if( count++ == 10 ){//休眠10秒之后,将SIGINT信号取消屏蔽
sigprocmask(SIG_SETMASK,&o,NULL);
printf("recover block\n");
sleep(3);
}
}
}
演示结果
- 前10秒之前接收到ctrl+c信号之后,可以看到比特位第2位变为1,SIGINT被屏蔽。10秒之后取消阻塞