sleep2在apue中工作不正常?

时间:2014-01-23 09:39:49

标签: c linux signals

sleep2的apue中的代码如下:

#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

static jmp_buf env_alrm;

static void sig_alrm(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));
}

int main(void)
{
    while(1)
    {
        sleep2(1);
        printf("test\n");
    }
    return 0;
}

代码的输出只是一个字符串“test”,然后挂起

根据我的理解,sleep2功能的工作原理如下:

  1. jmp_buf env_alrm设置为0
  2. 当程序第一次调用sleep2时,alarm(nsecs)将被调用
  3. 在nsecs时,sig_alrm将被调用,longjpm将env_alrm结构设置为1
  4. 然后它跳转到if(setjmp(env_alrm) == 0),但它不是真的,所以它运行语句return alarm(0)
  5. 在第二次调用sleep2时,struct jmp_buf env_alrm的值为1,因此alrm(nsecs)不会被调用,在我看来,这是使得功能不正常的原因所以我改变了代码如下:

    #include <setjmp.h>
    #include <signal.h>
    #include <unistd.h>
    #include <stdio.h>
    
    static jmp_buf env_alrm;
    
    static void sig_alrm(int signo)
    {
        longjmp(env_alrm, 1);
    }
    
    unsigned int sleep2(unsigned int nsecs)
    {
        if(signal(SIGALRM, sig_alrm) == SIG_ERR)
        {
            return (nsecs);
        }
    
        alarm(nsecs);
        if(setjmp(env_alrm) == 0)
        {
            pause();
        }
    
        return (alarm(0));
    }
    
    int main(void)
    {
        while(1)
        {
            sleep2(1);
            printf("test\n");
        }
        return 0;
    }
    

    但是,第二个程序产生的输出与第一个程序相同,所以我的问题是:

    是什么让两个程序只打印一个“测试”然后挂起?

1 个答案:

答案 0 :(得分:0)

您的代码与书上的代码完全相同。每当信号处理程序longjmp()到sleep2()时,alarm()从未(并且永远不会)再次执行。对于你的问题,我建议你继续阅读本书,直到sig_setjmp()函数部分。 由于我不知道你的系统,我认为挂断很可能是因为longjmp()不能恢复信号掩码。这意味着您第一次进入信号处理程序并且系统会自动屏蔽此信号以避免重入。当处理程序返回此屏蔽信号(在您的情况下为SIGALRM)时,将取消屏蔽(恢复)。 POSIX没有定义longjmp()是否应该恢复此信号。所以你可能在处理程序中屏蔽了SIGALRM并且没有取消屏蔽它。因此程序卡在第二个循环上。 要验证这一点,您可以在sig_alrm()处理程序中使用pr_mask()函数。这是作者编写的用于打印当前进程掩码的函数。让我通知结果。