我想知道当我的程序同时处理其他信号时是否有可能被信号中断,我试图用以下方法模拟它:
#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
总是这样吗?
答案 0 :(得分:6)
引用sigaction(2)
联机帮助页:
信号程序通常用导致它们的信号执行 调用被阻止,但其他信号可能仍然发生。全局信号掩码 定义当前阻止传递到进程的信号集。 进程的信号掩码从其父进程初始化 (通常是空的)。可以通过
sigprocmask(2)
电话或何时更改 信号传递给过程。
您可以使用SA_NODEFER
标志控制信号是否在其信号处理程序中自动阻止。
答案 1 :(得分: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
编辑,SysV会立即生成 new SIGCLD
,并且您的处理程序将以递归方式输入。这使得它看起来好像排队了,而没有实际排队。
有关Linux信号的更多信息,请参阅(例如)http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html。