?: sigpending函数返回一信号集,对于调用进程而言,其中的各信号是阻塞不能递送的,因而也一定是当前未决的。该信号集通过set参数返回。

#include <signal.h>

int sigpending(sigset_t *set);
//返回值:若成功,返回0;若出错,返回−1

实例

图10-15展示了很多前面说明过的信号功能。

#include "apue.h"

static void sig_quit(int);

int
main(void)
{
    sigset_t newmask, oldmask, pendmask;

    if (signal(SIGQUIT, sig_quit) == SIG_ERR)
        err_sys("can't catch SIGQUIT");

    /*
     * Block SIGQUIT and save current signal mask.
     */
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGQUIT);
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        err_sys("SIG_BLOCK error");

    sleep(5);    /* SIGQUIT here will remain pending */
    //进程阻塞SIGQUIT信号,保存了当前信号屏蔽字(以便以后恢复),然后休眠5秒。

    //在此期间所产生的退出信号SIGQUIT都被阻塞,不递送至该进程,直到该信号不再被阻塞。
    //在5秒休眠结束后,检查该信号是否是未决的,然后将SIGQUIT设置为不再阻塞。
    if (sigpending(&pendmask) < 0)
        err_sys("sigpending error");
    if (sigismember(&pendmask, SIGQUIT))
        printf("\nSIGQUIT pending\n");

    /*
     * Restore signal mask which unblocks SIGQUIT.
     */
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        err_sys("SIG_SETMASK error");
    printf("SIGQUIT unblocked\n");

    sleep(5);    /* 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)
        err_sys("can't reset SIGQUIT");
}

图10-15 信号设置和sigprocmask实例

进程阻塞SIGQUIT信号,保存了当前信号屏蔽字(以便以后恢复),然后休眠5秒。

在此期间所产生的退出信号SIGQUIT都被阻塞,不递送至该进程,直到该信号不再被阻塞。在5秒休眠结束后,检查该信号是否是未决的,然后将SIGQUIT设置为不再阻塞。

注意,在设置 SIGQUIT 为阻塞时,我们保存了老的屏蔽字。为了解除对该信号的阻塞,用老的屏蔽字重新设置了进程信号屏蔽字(SIG_SETMASK)。另一种方法是用SIG_UNBLOCK使阻塞的信号不再阻塞。但是,应当了解如果编写一个可能由其他人使用的函数,而且需要在函数中阻塞一个信号,则不能用SIG_UNBLOCK简单地解除对此信号的阻塞,这是因为此函数的调用者在调用本函数之前可能也阻塞了此信号。在这种情况下必须使用SIG_SETMASK将信号屏蔽字恢复为先前的值,这样也就能继续阻塞该信号。10.18节的system函数部分有这样的一个例子。

在休眠期间如果产生了退出信号,那么此时该信号是未决的,但是不再受阻塞,所以在sigprocmask 返回之前,它被递送到调用进程。

从程序的输出中可以看到这一点:SIGQUIT 处理程序(sig_quit)中的printf语句先执行,然后再执行sigprocmask之后的printf语句。

然后该进程再休眠5秒。如果在此期间再产生退出信号,那么因为在上次捕捉到该信号时,已将其处理方式设置为默认动作,所以这一次它就会使该进程终止。在下列输出中,当我们在终端键入退出字符Ctrl+\时,终端打印^\(终端退出字符):

$ ./a.out
^\             产生信号一次(在5s之内)
SIGQUIT pending     从sleep返回后
caught SIGQUIT         在信号处理程序中
SIGQUIT unblocked    从sigprocmask返回后
^\Quit(coredump)     再次产生信号
$ ./a.out
^\^\^\^\^\^\^\^\^\^\  产生信号10次(在5 s之内)
SIGQUIT pending
caught SIGQUIT      只产生信号一次
SIGQUIT unblocked
^\Quit(coredump)     再产生信号

shell发现其子进程异常终止时输出QUIT(coredump)信息。

注意,第二次运行该程序时,在进程休眠期间使SIGQUIT信号产生了10次,但是解除了对该信号的阻塞后,只向进程传送一次SIGQUIT。从中可以看出在此系统上没有将信号进行排队。

results matching ""

    No results matching ""