【问题标题】:signal interactive in unixunix中的信号交互
【发布时间】:2015-06-23 08:45:23
【问题描述】:

下面的代码让我很困惑

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

【问题讨论】:

    标签: c unix signals


    【解决方案1】:

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

    如果您在 sleep2 函数中发送 SIGINT (Ctrl + C),则会调用其信号处理程序 sig_int,一旦它返回,它会导致 pause 返回。最后,return(alarm(0)); 会返回之前设置的警报之前剩余的秒数(如果要发送)。

    因此,如果您在 5 秒内发送 SIGINT(即在 alarm(nsecs) 调用发送 SIGALRM 之前),那么 sleep2 将返回 5-x 秒数(x 大致是自程序的开始)。

    这基本上取决于谁先醒来pause:您发送的SIGINTalarm(nsecs) 发送的SIGALRM 呼叫。而unslept的输出将以此为基础。


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

    setjmp/longjmp 组合的思想是用来保证程序不会卡在pause,以防SIGALRM被传递之前pause被调用。如果 setjmp/longjmp 不存在并且在pause() 启动之前处理了信号SIGALRM,那么pause() 将永远等待一个信号,因为它不知道之前的SIGALRM 传递。

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

    【讨论】:

    • 最后一段对于理解代码发生了什么至关重要。 SIGINT 的处理程序的目标是它运行超过 5 秒(因此存在嵌套循环),它表明这不是 sleep() 的良好实现,因为它会在 @ 时取消 sig_int() 的执行987654353@ 被触发。该示例的目的是表明,即使 longjmp / setjmp 解决了与 pause() 的竞争条件,它们也会引入可能在执行过程中取消其他处理程序的问题。
    猜你喜欢
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多