unix中的信号交互

时间:2015-06-23 08:45:23

标签: c unix signals

我得到以下代码让我感到困惑

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然后退出吗?

1 个答案:

答案 0 :(得分:3)

首先,SIGINTSIGALRM分别为mainsleep2设置了两个信号处理程序。然后设置一个警报,在SIGALRM(即5)中传递nsecs并调用pause,等待任何信号。

如果在sleep2函数中发送SIGINT( Ctrl + C ),则调用其信号处理程序sig_int,一旦返回,就会导致{{1} } 回来。最后,pause返回先前设置的警报之前剩余的秒数(如果要传递)。

因此,如果您在5秒内发送return(alarm(0));(即在通过SIGINT电话发送SIGALRM之前),则alarm(nsecs)将返回sleep2秒(5-x大致是自程序启动以来经过的秒数)。

这主要取决于谁首先唤醒xpause您发送的SIGINTSIGALRM来自alarm(nsecs)的{​​{1}}。 unslept的输出将基于此。

我看到这是本书APUE中的一个例子。它解释了为什么在这里使用setjmp / longjmp。

setjmp / longjmp组合的思想用于确保程序不会卡在pause中以防SIGALRMpause之前传递调用。如果setjmp / longjmp不存在并且在SIGALRM开始之前处理了信号pause(),那么pause()将永远等待信号,因为它不知道之前发送的SIGALRM

本书(第10章信号)继续解释为什么即使这不完美,因为longjmp(在SIGALRM处理程序中)可能会中止其他信号处理程序。