C中的信号处理 – 中断中断

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

#include #include #include #include #include #include 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 

总是这样吗?

引用sigaction(2)联机帮助页:

信号例程通常使用导致其调用被阻止的信号执行,但是其他信号可能仍然发生。 全局信号掩码定义当前阻止传递到进程的信号集。 进程的信号掩码从其父进程(通常为空)初始化。 可以使用sigprocmask(2)调用或将信号传递给进程来更改它。

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

据我所知,这些特定待处理信号的传递顺序并未定义。 然而,除了实时信号之外,信号(大部分是SIGCLD的例外,传统上通过“作弊”完成)“非排队”。 非排队方面意味着如果您阻止了信号X,然后raiseraise两次(就像上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. 

(这些是类似SIGSEGVSIGBUS东西。)通常,您可以通过使用信号阻塞掩码来控制传递的顺序:在某个时刻解除阻止任何特定信号,并且那些是那时可以传递的信号。 。

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

SIGCLD的特例来自System V,它最初是通过在每个SIGCLD交付时将处理程序重置为SIG_DFL来实现的。 (实际上,SysV使用所有信号执行SA_RESETHAND无论您是否需要,都可以有效地实现SA_RESETHAND 。)默认操作是丢弃信号,就像处理程序是SIG_IGN 。 这当然会在多个子进程完成之前创建竞争条件,然后处理程序可以执行其操作。 但是,不是块/解块模型,而是SysV人员进行了一次黑客攻击:在你的SIGCLD处理程序结束时,你会调用signal(SIGCLD, handler); 修复处理程序。 此时,如果有任何尚未wait退出子项,SysV将立即生成新的 SIGCLD ,并且递归地输入您的处理程序。 这使得它看起来好像排队了,而没有实际排队。

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