C语言中的信号处理——中断中的中断

C语言中的信号处理——中断中的中断,c,signals,C,Signals,我想知道当我的程序同时处理其他信号时,是否可能被信号中断,我尝试用以下方法模拟它: #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,

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

#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;
}

总是这样吗?

引用
sigaction(2)
manpage:

信号例程通常与导致其错误的信号一起执行 调用被阻止,但可能还会出现其他信号。全局信号掩码 定义当前阻止传递到进程的信号集。 进程的信号掩码从其父进程的信号掩码初始化 (通常为空)。可以通过调用
sigprocmask(2)
或在 向进程发送一个信号


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

据我所知,这些特定挂起信号的传递顺序没有定义。然而,除了实时信号外,信号通常是(大多数情况下,
SIGCLD
有一个例外,它传统上是通过“欺骗”来完成的”)“非排队”。非排队特性意味着,如果信号X被阻塞,然后
将其提升两次(就像上面对
SIGUSR1
所做的那样),则只能交付一次

至少一个系统(MacOS)上记录的唯一订购是:

(例如
SIGSEGV
SIGBUS
)通常,您可以通过使用信号阻塞掩码来控制传输顺序:在某个点解除对任何特定信号的阻塞,这些信号就是在该点可以传输的信号

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

SIGCLD
的特例来自systemv,它最初是通过在每次
SIGCLD
交付时将处理程序重置为
SIG_DFL
来实现的。(事实上,SysV对所有信号都这样做,有效地实现了
SA_RESETHAND
,不管您是否想要它。)默认操作是丢弃信号,就像处理程序是
SIG_IGN
。当然,当多个子进程在处理程序能够完成其任务之前完成时,这就产生了竞争条件。然而,SysV人员没有采用阻塞/解除阻塞模型,而是采用了一种破解方法:在
SIGCLD
处理程序的末尾,您将调用
signal(SIGCLD,handler)
来修复处理程序。此时,如果有任何退出的子级尚未等待,SysV将立即生成一个新的
SIGCLD
,您的处理程序将以递归方式输入。这使得信号看起来像是在排队,而实际上并没有排队


有关Linux信号的更多信息,请参阅(例如)。

它实际上依赖于处理器和操作系统。一般来说,许多CPU都支持不同优先级的中断,这样高优先级的中断可以在低优先级的中断运行时跳入。POSIX信号不是硬件中断,所以处理器本身在这里不成问题。好吧,我一定错过了这一点。这也值得注意(我认为从文档中不清楚,尽管这是非常合乎逻辑的)您提供给
sigaction
sau掩码是一个要阻止的附加信号掩码,而不是一个要设置的新掩码。因此,如果您(1)要求用显式阻止信号Y的
sau掩码
捕获信号X(由于您关闭了
sau NODEFER
而隐式阻止X),然后(2)使用
sigprocmask
阻止信号Z,然后(3)实际捕获信号X,您的处理程序在所有X、Y和Z都被阻止的情况下运行。Linux文档中可能不清楚这一点;OS X(通过FreeBSD)关于新掩码是如何形成的,文档非常清楚。
currently blocking:
blocking SIGUSR1, SIGUSR2
currently blocking:
SIGUSR1
SIGUSR2
raising
using sigsuspend
start - other
SIGUSR2
end - other
start
SIGUSR1
end
end of program
If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.