5

我想知道当我的程序同时处理其他信号时是否有可能被信号中断,我尝试用以下方法模拟它:

#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>

void sig_output()
{
    sigset_t set;
    sigprocmask(0,NULL,&set);
    printf("currently blocking:");
    if (sigismember(&set,SIGUSR1))
        printf("\nSIGUSR1");
    if(sigismember(&set,SIGUSR2))
        printf("\nSIGUSR2");
    printf("\n");
    return ;
}

void sig_handler(int sig)
{
    raise(SIGUSR1);    
    printf("start\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end\n");
    return ;
}

void other_sig_handler(int sig)
{  
    printf("start - other\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end - other\n");
    return ;
}

int main()
{
    sig_output();
    struct sigaction a;
    a.sa_handler=sig_handler;
    a.sa_flags=0;
    sigset_t set,old;
    //blocking SIGUSR1,SIGUSR2
    sigemptyset(&set);
    sigaddset(&set,SIGUSR1);
    sigaddset(&set,SIGUSR2);
    printf("blocking SIGUSR1, SIGUSR2\n");
    sigprocmask(SIG_SETMASK,&set,&old);
    sig_output();
    //adding handles for SIGUSR1,SIGUSR2
    sigemptyset(&(a.sa_mask));
    sigaction(SIGUSR1,&a,NULL);
    a.sa_handler=other_sig_handler;
    sigaction(SIGUSR2,&a,NULL);
    printf("poczatek wysylania \n");
    raise(SIGUSR1);
    raise(SIGUSR2);
    raise(SIGUSR1);
    printf("using sigsuspend\n");
    sigsuspend(&old);
    printf("end of program\n");
    return 0;
}

每次我运行这个程序时,我都会得到

currently blocking:
blocking SIGUSR1, SIGUSR2
currently blocking:
SIGUSR1
SIGUSR2
raising
using sigsuspend
start - other
SIGUSR2
end - other
start
SIGUSR1
end
end of program

总是这样吗?

4

2 回答 2

6

据我所知,这些特定未决信号的传递顺序尚未定义。但是,信号(大多数情况下;一个例外SIGCLD,传统上是通过“作弊”来完成的)“非排队”,实时信号除外。非排队方面意味着如果您将信号 X 阻塞,然后raise它两次(如您在上面对 执行的操作SIGUSR1),您只会将其发送一次。

在至少一个系统 (MacOS) 上记录的唯一顺序是:

If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.

SIGSEGV(这些是和之类的东西SIGBUS。)通常,您可以通过使用信号阻塞掩码来控制传递顺序:在某个点取消阻塞任何特定信号,并且那些是可以在该点传递的信号。

如果您不设置SA_NODEFER,则处理程序入口处的阻塞掩码将始终阻止您的处理程序正在处理的任何信号,这样您就不必担心递归。

的特殊情况SIGCLD来自 System V,它最初通过SIG_DFL在每次SIGCLD交付时重置处理程序来实现这一点。(事实上​​,SysV 对所有信号都这样做了,SA_RESETHAND不管你是否想要它都有效地实现了它。)默认操作是丢弃信号,就好像处理程序是SIG_IGN. 当多个子进程在处理程序执行其操作之前完成时,这当然会产生竞争条件。但是,SysV 人员没有使用阻塞/解除阻塞模型,而是进行了修改:在SIGCLD处理程序结束时,您会调用signal(SIGCLD, handler);以修复处理程序。那时,如果有任何已退出的子节点尚未被wait-ed 处理,SysV 将立即生成一个新的 SIGCLD,并且您的处理程序将被递归输入。这使得信号看起来像是在排队,但实际上没有排队。

有关 Linux 信号的更多信息,请参阅(例如)http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html

于 2012-04-10T18:18:44.983 回答
6

引用手册sigaction(2)页:

信号例程通常会在导致其调用被阻塞的信号的情况下执行,但可能还会出现其他信号。全局信号掩码定义了当前阻止传递给进程的一组信号。进程的信号掩码从其父进程的信号掩码(通常为空)初始化。它可以通过sigprocmask(2)调用或在将信号传递给进程时进行更改。

SA_NODEFER您可以使用标志控制信号是否在其信号处理程序中自动阻塞。

于 2012-04-10T18:07:52.197 回答