《unix高级环境编程》信号——信号集

信号集

          信号集是表示多个信号的数据类型,这里的信号集数据类型是 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高级环境编程》

你可能感兴趣的:(Unix高级环境编程,信号集,sigpending函数,sigprocmask函数)