一、引言
从上一篇文章我们知道了在内核当中如果接收到了信号不做事情的话,那么就会出现进程的中断,此时就需要把信号做成屏蔽的效果
二、函数原型
1、sigprocmask函数
头文件:#include <signal.h>
功能:读取或更改进程的信号屏蔽字,将不认识的或者不希望接收的信号屏蔽,保证进程的正常执行。
原型:int sigprocmask(int how, const sigset_t *set, sigset_t *oset);参数说明:
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
返回值:若成功则为0,若出错则为-1
参数how可选值 SIG_BLOCK 信号锁上(屏蔽) SIG_UNBLOCK 信号不锁(解除阻塞) SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,相当于 设置当前信号屏蔽字为集所指向的值 信号集操作函数如下
#include <signal.h> /* Clear all signals from SET. */ int sigemptyset(sigset_t *set);// 清空信号集 /* Set all signals in SET. */ int sigfillset(sigset_t *set);// 所有信号加进去 32 33 是没有的 int sigaddset(sigset_t *set, int signo);// 增加信号 int sigdelset(sigset_t *set, int signo);//删除信号集的某个信号 int sigismember(const sigset_t *set, int signo);// 信号是否在集合里面 /* Return 1 if SIGNO is in SET, 0 if not. */
示例
1、实现基本步骤
- 先准备一个信号集(可以理解为一个装屏蔽信号的容器或理解为把好友加入黑名单)
- 信号容器初始化
- 添加屏蔽的信号
- 调用sigprocmask对设定的信号集进行屏蔽
2、代码
//准备信号容器
sigset_t arr;
//容器初始化
sigemptyset(&arr);
//添加屏蔽的信号
sigaddset(&arr,SIGUSR1);
sigaddset(&arr, SIGUSR2);
if (sigprocmask(SIG_BLOCK,&arr,NULL) < 0)
{
perror("sigprocmask error");
exit(0);
}
while (true)
{
cout << "当前进程运行中 ...pid =" << getpid() << endl;
sleep(1);
}
3、运行效果
从下图可以发现,此时一直给进程发送信号,都不会被中断
4、分析
通过上述例子,屏蔽信号真的就像是女生把男朋友拉入黑名单,但是女生又想知道男朋友到底有没有给她打电话发消息 (可能心软了就把他移出黑名单)。那么如果想知道有没有联系就得使用sigpending函数,如下
2、sigpending函数
#include <signal.h>
int sigpending(sigset_t *set);功能:读取当前进程的未决信号集(未决就表示这个信号还没有绑定响应的处理函数,即没有决定是把他移出黑名单还是让他永远待在黑名单,只是想看看他到底有没有联系)
返回值:若成功则为0,若出错则为-1
示例
1、代码
//准备信号容器
sigset_t arr;
//容器初始化
sigemptyset(&arr);
//添加屏蔽的信号
sigaddset(&arr,SIGUSR1);
sigaddset(&arr, SIGUSR2);
if (sigprocmask(SIG_BLOCK,&arr,NULL) < 0)
{
perror("sigprocmask error");
exit(0);
}
while (true)
{
cout << "当前进程运行中 ...pid =" << getpid() << endl;
sleep(10);
//查看未决信号集(黑名单)
if (sigpending(&arr) == 0)
{
//判断未决信号是谁发的
cout << "黑名单中的电话打来" << endl;
if (sigismember(&arr,SIGUSR1))
{
cout << "黑名单中的SIGUSR1打来电话" << endl;
}
if (sigismember(&arr, SIGUSR2))
{
cout << "黑名单中的SIGUSR2打来电话" << endl;
}
}
}
return 0;
注意:
①if (sigpending(&arr) == 0)只是判断函数能不能执行成功,而不是有没有成功把信号放到信号集里面
②好像未决信号集(未处理的信号)无法用sigemptyset清空(有待进一步研究)
2、运行结果
如下图,给10431进程发送四次信号,进程这边都显示了是谁发来信号(这时候女生就知道黑名单中的男朋友打来几次电话了)