一、信号集及信号集操作函数
信号集被定义为一种数据类型:
typedef struct
{
unsigned long sig[_NSIG_WORDS];
} sigset_t
信号集用来描述信号的集合,linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。下面是为信号集操作定义的相关函数:
#include <signal.h>
int sigemptyset(sigset_t *set)
功能:初始化由set指定的信号集,信号集里面的所有信号被清空;
参数:set信号集
返回值:成功0,失败-1
int sigfillset(sigset_t *set)
功能:调用该函数后,set指向的信号集中将包含linux支持的64种信号;
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指向的信号集中。
二、信号阻塞与信号未决
每个进程都有一个用来描述哪些信号递送到进程时将被阻塞的信号集,该信号集中的所有信号在递送到进程后都将被阻塞。下面是与信号阻塞相关的几个函数:
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset));
功能:设置进程的信号屏蔽字
参数:how
SIG_BLOCK 在进程当前阻塞信号集中添加set指向信号集中的信号
SIG_UNBLOCK 如果进程阻塞信号集中包含set指向信号集中的信号,则解除对该信号的阻塞
SIG_SETMASK 更新进程阻塞信号集为set指向的信号集
参数:set新的信号屏蔽字
参数:oldset原先的信号屏蔽字
如果参数set为空,how值就没有意义,此时该调用的目的是把当前信号屏蔽字保存在oset中
返回值:成功返回0
int sigpending(sigset_t *set))
功能:将被进程阻塞的信号中听在待处理状态的一组信号写到参数set指定的信号集中
参数:set保存未决信号的信号集
返回值:成功0,失败-1
int sigsuspend(const sigset_t *mask)
功能:用于在接收到某个信号之前, 临时用mask替换进程的信号掩码, 并暂停进程执行,直到收到信号为止。sigsuspend 返回后将恢复调用之前的号掩码。信号处理函数完成后,
进程将继续执行
参数:mask临时信号屏蔽字
返回值:该系统调用始终返回-1,并将errno设置为EINTR。
三、应用举例
实例一:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static void sig_quit(int);
int main(void)
{
sigset_t newmask, oldmask, pendingmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR)
{
fprintf(stderr, "can't catch SIGQUIT\n");
exit(1);
}
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)//当前进程屏蔽SIGQUIT信号
{
fprintf(stderr, "SIG_BLOCK error\n");
exit(1);
}
sleep(5);
if (sigpending(&pendingmask) < 0)//获得进程的未决信号
{
fprintf(stderr, "sigpending error\n");
exit(1);
}
if (sigismember(&pendingmask, SIGQUIT))//查看未决信号集合中是否存在SIGQUIT
printf("\nSIGQUIT pending\n");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)//恢复以前的信号屏蔽字,如果刚才接收到的未决信号集中存在SIGQUIT信号,则会调用它的信号处理函数
{
fprintf(stderr, "SIG_SETMASK error\n");
exit(1);
}
printf("SIGQUIT unblocked\n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT\n");
//恢复进程对SIGQUIT的默认处理
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
{
fprintf(stderr, "can't reset SIGQUIT\n");
exit(0);
}
}
实例二:
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void handler(int sig) //信号处理程序
{
if(sig == SIGINT)
printf("SIGINT sig");
else if(sig == SIGQUIT)
printf("SIGQUIT sig");
else
printf("SIGUSR1 sig");
}
int main()
{
sigset_t new,old,mask;
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
sigaction(SIGQUIT, &act, 0);
sigaction(SIGUSR1, &act, 0);
sigemptyset(&new);
sigaddset(&new, SIGINT);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &new, &old);
if(sigsuspend(&mask) != -1)/*当接受到的信号不在mask中,就直接返回,屏蔽字恢复到原来的,该转换是原子的,如果在调用期间接受到SIGQUIT信号,那么该函数返回后将执行SIGQUIT的信号处理函数,如果先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,因为SIGUSR1是前面阻塞的*/
printf("sigsuspend error\n");
printf("After sigsuspend\n");
sigprocmask(SIG_SETMASK, &old, NULL);
return 0;
}
参考文章: