信号集
信号集是表示多个信号的数据类型,这里的信号集数据类型是 sigset_t,包含五个处理信号集的函数:
/* 信号集 */
#include <signal.h>
int sigemptyset(sigset_t *set);//初始化由set所指向的信号集,清空信号集;
int sigfillset(sigset_t *set);//初始化由set所指向的信号集,使其包括所有信号;
int sigaddset(sigset_t *set, int signo);//把指定的信号signo添加到由set所指的信号集中;
int sigdelset(sigset_t *set, int signo);//把指定的信号signo从由set所指定的信号集中删除;
//前面四个函数返回值:若成功则返回0,若出错则返回-1;
int sigismember(const sigset_t *set, int signo);//判断指定的信号signo是否在由set所指的信号集中;
//返回值:若为真则返回1,若为假则返回0,若出错则返回-1;
/*
* 说明:
* 所有应用程序使用信号集之前,要对该信号集调用sigemptyset或sigfillset一次;
*/
sigprocmask 函数
在前面我们提到,task_struct 结构有一个blocked 成员(我们称之为“信号屏蔽字”),它指定了进程阻塞的信号,被阻塞的信号将不能被递送给进程,直到进程解除阻塞。在信号被阻塞时,内核将其放置到待决列表上。如果同一个信号在阻塞期间被发送了多次,则在待决列表中只放置一次。也就是说,不管发送了多少相同的信号,在进程删除阻塞后,都只会接收到一个信号。调用函数sigprocmask 可以检测或更改其信号屏蔽字。在调用 sigprocmask 后如果有任何未决的、不再阻塞的信号,则在 sigprocmask 返回前,至少会将其中一个信号递送给该进程。
/* sigprocmask 函数 */
/*
* 函数功能:检查或更改信号屏蔽字,也可同时执行这两个操作;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
/*
* 说明:
* 若oset是非空指针,那么进程的当前信号屏蔽字通过oset返回;
* 若set是非空指针,则参数how指示如何修改当前信号屏蔽字;
* 若set是空指针,则不改变该进程的信号屏蔽字,how的值就没有意义;
* 参数how可选以下值:
* (1)SIG_BLOCK 该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集。set包含了我们希望阻塞的附加信号;
* (2)SIG_UNBLOCK 该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集补集的交集;set包含我们希望解除阻塞的附加信号;
* (3)SIG_SETMASK 该进程新的信号屏蔽字将被set指向的信号集的值所代替;
* SIG_BLOCK是"或"操作,而SIG_SETMASK则是赋值操作;
* 注意:SIGKILL 和 SIGSTOP 信号是不能阻塞的;
*/
sigpending 函数
sigpending 函数返回信号集,其中的各个信号对于调用进程是阻塞的而不能传递,该信号集通过set参数返回。
/* sigpending函数 */
/*
* 函数功能:返回信号集;
* 返回值:若成功则返回0,若出错则返回-1;
* 函数原型:
*/
#include <signal.h>
int sigpending(sigset_t *set);
测试程序:
#include "apue.h"
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
static void sig_quit(int signo);
int main()
{
sigset_t newmask,oldmask,pendmask;
if(signal(SIGQUIT,sig_quit) == SIG_ERR)
{
err_sys("signal() error");
exit(-1);
}
//初始化信号集
sigemptyset(&newmask);
//添加一个SIGQUIT信号
sigaddset(&newmask,SIGQUIT);
//将newmask信号集设置为阻塞,原信号集保存在oldmask中
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) == -1)
{
err_sys("SIG_BLOCK error");
exit(-1);
}
sleep(5);
//获取阻塞的信号集
if(sigpending(&pendmask) == -1)
{
err_sys("sigpending() error");
exit(-1);
}
//判断SIGQUIT是否是阻塞的
if(sigismember(&pendmask,SIGQUIT))
printf("\nSIGQUIT is pending.\n");
//恢复原始的信号集
if(sigprocmask(SIG_SETMASK,&oldmask,NULL) == -1)
{
err_sys("SIG_SETMASK error");
exit(-1);
}
printf("SITQUIT unblocked\n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT.\n");
if(signal(SIGQUIT,SIG_DFL) == SIG_ERR)
{
err_sys("can't reset SIGQUIT");
exit(-1);
}
}
输出结果:
$ ./sigset
^\
SIGQUIT is pending.
caught SIGQUIT.
SITQUIT unblocked
$ ./sigset
^\^\^\^\^\^\
SIGQUIT is pending.
caught SIGQUIT.
SITQUIT unblocked
在程序第二次
sleep 时,产生了多个
SIGQUIT 信号,此时被
pending,解除了
mask 后,只产生了一次
action,也说明了在同一时刻产生多次同一种信号,不会对信号排队。
参考资料:
《UNIX高级环境编程》