我得到以下代码让我感到困惑
static jmp_buf env_alrm;
static void sig_alrm1(int signo){
longjmp(env_alrm,1);
}
unsigned int sleep2(unsigned int nsecs){
if(signal(SIGALRM ,sig_alrm) == SIG_ERR)
return(nsecs);
if(setjmp(env_alrm) == 0){
alarm(nsecs);
pause();
}
return(alarm(0));
}
static void sig_int(int);
int main(void){
unsigned int unslept;
if(signal(SIGINT,sig_int) == SIG_ERR)
err_sys("signal (sigint) error");
unslept = sleep2(5);
printf("sleep2 return ed :%u\n" ,unslept);
exit(0);
}
static void sig_int(int signo){
int i,j;
volatile int k;
printf("\nsig_int staring\n");
for(i = 0;i<30000;i++)
for(j = 0;j<4000;j++)
k += i *j;
printf("sig_int finished");
}
当睡眠功能正常时,如果按ctrl + c。 真正发生了什么?它会忽略SIGALRM并运行sig_int然后退出吗?
答案 0 :(得分:3)
首先,SIGINT
和SIGALRM
分别为main
和sleep2
设置了两个信号处理程序。然后设置一个警报,在SIGALRM
(即5)中传递nsecs
并调用pause
,等待任何信号。
如果在sleep2
函数中发送SIGINT( Ctrl + C ),则调用其信号处理程序sig_int
,一旦返回,就会导致{{1} } 回来。最后,pause
返回先前设置的警报之前剩余的秒数(如果要传递)。
因此,如果您在5秒内发送return(alarm(0));
(即在通过SIGINT
电话发送SIGALRM之前),则alarm(nsecs)
将返回sleep2
秒(5-x
大致是自程序启动以来经过的秒数)。
这主要取决于谁首先唤醒x
:pause
您发送的SIGINT
或SIGALRM
来自alarm(nsecs)
的{{1}}。 unslept
的输出将基于此。
我看到这是本书APUE中的一个例子。它解释了为什么在这里使用setjmp / longjmp。
setjmp / longjmp组合的思想用于确保程序不会卡在pause
中以防SIGALRM
在 pause
之前传递调用。如果setjmp / longjmp不存在并且在SIGALRM
开始之前处理了信号pause()
,那么pause()
将永远等待信号,因为它不知道之前发送的SIGALRM
。
本书(第10章信号)继续解释为什么即使这不完美,因为longjmp(在SIGALRM处理程序中)可能会中止其他信号处理程序。