1、信号集
POSIX标准定义了数据类型sigset_t
#include <signal.h>
int sigemptyset(sigset_t *set);
初始化一个信号集,使其不包括任何信号
int sigfillset(sigset_t *set);
用来初始化一个信号集,使其包括所有信号
int sigaddset(sigset_t *set, int signum);
用来向set指定的信号集中添加由signum指定的信号
int sigdelset(sigset_t *set, int signum);
用来从set指定的信号集中删除由signum指定的信号
int sigismember(const sigset_t *set, int signum);
用来测试信号signum是否包括在set指定的信号集中
2、信号屏蔽
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
(1)sigprocmask函数int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
每个进程都有一个信号屏蔽码,它规定了当前阻塞而不能传递给该进程的信号集,调用函数sigprocmask可以检测或更改进程的信号屏蔽码。
如果oldset是非空的,则该进程之前的信号屏蔽码通过oldset返回;如果参数set是非空指针,则该函数将根据参数how来修改当前屏蔽码,how
的取值如下:
The behavior of the call is dependent on the value of how, as follows.
SIG_BLOCK
The set of blocked signals is the union of the current set and the set argument.
将进程新的信号屏蔽码设置为当前信号屏蔽码和set指向信号集的并集
SIG_UNBLOCK
The signals in set are removed from the current set of blocked signals. It is permissible to attempt to unblock a signal which is not blocked.
将进程新的信号屏蔽码设置为当前信号屏蔽码中,删除set所指向信号集,即set包含了我们希望解除阻塞的信号。即使
对当前信号屏蔽码中不存在的信号使用SIG_UNBLOCK也是合法操作。
SIG_SETMASK
The set of blocked signals is set to the argument set.
将进程新的信号屏蔽码设置为set指向的值
(2)sigpending函数int sigpending(sigset_t *set);
函数sigpending用来获取调用进程因被阻塞而不能传递和当前未决的信号集。该信号集通过参数set返回
#include <stdio.h>
#include <signal.h>
void hand_signal(int signo)
{
printf("rece SIGINT\n");
}
int main()
{
sigset_t newmask, oldmask, pendmask;
signal(SIGINT, hand_signal);
//收到信号之后会被唤醒
sleep(30);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
//屏蔽信号SIGINT
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
//不会被SIGINT信号唤醒
sleep(10);
//获取未决信号队列
sigpending(&pendmask);
//检查未决信号队列中是否有SIGINT
switch(sigismember(&pendmask, SIGINT))
{
case 0:
{
printf("the SIGINT is not in pending queue\n");
break;
}
case 1:
{
printf("the SIGINT is in pending queue\n");
break;
}
default:
break;
}
//恢复屏蔽码
sigprocmask(SIG_SETMASK, &oldmask, NULL);
while(1);
return 0;
}
(3)sigsuspend函数int sigsuspend(const sigset_t *mask);
将进程的信号屏蔽码设置为mask,然后与pause函数一样等待信号的发生并执行完信号处理函数。
信号处理函数执行完后再把进程的信号屏蔽码设置为原来的屏蔽字,然后sigpending函数才返回。
sigpending函数保证改变进程的屏蔽码和将进程挂起等待信号是原子操作。
#include <stdio.h>
#include <signal.h>
void hand_signal(int signo)
{
printf("rece SIGINT\n");
}
int main()
{
sigset_t newmask, oldmask, zeromask;
signal(SIGINT, hand_signal);
sigemptyset(&newmask);
sigemptyset(&zeromask);
sigaddset(&newmask, SIGINT);
//屏蔽信号SIGINT
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
//临界区
//使用sigsuspend取消所有信号的屏蔽并等待信号的触发
sigsuspend(&zeromask);
/*
sigprocmask(SIG_SETMASK, &oldmask, NULL);
pause();
*/
sigprocmask(SIG_SETMASK, &oldmask, NULL);
while(1);
return 0;
}
如果使用
sigprocmask(SIG_SETMASK, &oldmask, NULL); pause();
会存在潜在debug,如果信号发生在sigprocmask之后,pause之前,则这个信号就会丢失掉了,且如果信号只发生一次,程序将永远挂起在pause上。