1 相关函数介绍
1.1 信号集函数
sigset_t表示一个信号集,如下为5个处理信号集的函数:
#include <signal.h>
//成功返回0,出错返回-1
int sigemptyset(sigset_t *set);
//成功返回0,出错返回-1
int sigfillset(sigset_t *set);
//成功返回0,出错返回-1
int sigaddset(sigset_t *set, int signo);
//成功返回0,出错返回-1
int sigdelset(sigset_t *set, int signo);
//成功返回1,出错返回0
int sigismember(const sigset_t *set, int signo);
sigemptyset用来初始化set指向的信号集,清除其中所有信号。
sigfillset用来初始化set指向的信号集,使得其包含所有信号。
sigaddset用来添加一个信号到信号集中。
sigdelset用来从信号集中删除一个信号。
1.2 sigprocmask函数
一个进程的信号屏蔽字规定了当前阻塞而不能递送给该进程的信号集。
函数sigprocmask可以检测或更改进程的信号屏蔽字。
#include <signal.h>
//成功返回0,出错返回-1
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指向的值。 |
SIG_BLOCK是或操作。SIG_SETMASK是赋值操作。
注意,不能阻塞SIGKILL和SIGSTOP信号。
在调用sigprocmask后如果有不再阻塞的信号,则在sigprocmask返回前,至少将其中之一递送给该进程。
sigprocmask是仅为单线程进程定义的。
1.3 sigpending函数
sigpending函数返回一信号集,对于调用进程而言,其中的各信号是阻塞不能递送的,因而一定是当前未决的。
#include <signal.h>
int sigpending(sigset_t *set);
即查下当前哪些信号是阻塞的。
2 使用sigprocmask函数阻塞SIGQUIT信号
如下进程会阻塞SIGQUIT信号,休眠5s。然后不再阻塞SIGQUIT信号,休眠5s。
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static void sig_quit(int);
int main(void)
{
sigset_t newmask, oldmask, pendmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR)
printf("can't catch SIGQUIT");
//1 Block SIGQUIT and save current signal mask.
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
printf("SIG_BLOCK error");
sleep(5); //2 SIGQUIT here will remain pending
if (sigpending(&pendmask) < 0)
printf("sigpending error");
if (sigismember(&pendmask, SIGQUIT))
printf("\nSIGQUIT pending\n");
//3 Restore signal mask which unblocks SIGQUIT.
printf("SIGQUIT unblocked >>>\n");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
printf("SIG_SETMASK error");
printf("SIGQUIT unblocked <<<\n");
sleep(5); //4 SIGQUIT here will terminate with core file
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT -------\n");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) //使SIGQUIT信号恢复默认行为(退出+core)
printf("can't reset SIGQUIT");
}
操作1:在第一次休眠5s内产生一次SIGQUITI信号(ctrl+\),在第二次休眠5s内产生一次SIGQUIT信号(ctrl+\)。
测试1结果如下:
^\SIGQUIT pending
SIGQUIT unblocked >>>
caught SIGQUIT -------
SIGQUIT unblocked <<<
^\ 退出(核心已转储)
在第一次休眠5s内产生的SIGQUIT信号,这时信号是未决的,在sigprocmask解除block后,SIGQUIT信号不再被阻塞,立刻被递送到调用进程,
信号处理函数sig_quit捕捉到SIGQUIT后,按照自定义处理,处理完后使SIGQUIT信号恢复为默认行为(退出+core)。
操作2:在第一次休眠5s内产生多次SIGQUITI信号(ctrl+\),在第二次休眠5s内产生一次SIGQUIT信号(ctrl+\)。
测试2结果如下:
^\^\^\^\^\
SIGQUIT pending
SIGQUIT unblocked >>>
caught SIGQUIT -------
SIGQUIT unblocked <<<
^\ 退出(核心已转储)
在第一次休眠5s内产生多个SIGQUIT信号,从结果来看,只有一个信号会递送给调用进程。