C语言中的alarm()和pause()函数会导致程序永久暂停。

3
在下面的程序中,pause被中断了一次,但之后就再也没有返回了。我已经设置了alarm来中断pause,所以我很困惑为什么pause永远不会返回?
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

static void sig_alrm(int);
static jmp_buf env_alrm;


int main(int arc, char **argv)
{

    int x;
    x = setjmp(env_alrm);
    printf("setjmp was created with return value: %d\n", x);

    if(signal(SIGALRM, sig_alrm) == SIG_ERR)
    {
            printf("Error settting SIGALRM\n");
            exit(1);
    }


    if((x!= 0) && (x!=1))
    {

            printf("Error setting setjmp\n");
            exit(1);
    }

    printf("Line next to setjmp\n");
    x = alarm(2);
    printf("Alarm set for 2 seconds, remaning secs from previous alarm: %d\n");
    pause();
    printf("Line next to pause()\n");
    alarm(0);
    return 0;
}

static void sig_alrm(int signo)
{
    longjmp(env_alrm, 1);
}

这里是输出,最后一行显示应用程序停顿的位置。
setjmp was created with return value: 0
Line next to setjmp
Alarm set for 2 seconds, remaining secs from previous alarm: 0
setjmp was created with return value: 1
Line next to setjmp
Alarm set for 2 seconds, remaining secs from previous alarm: 0
2个回答

4
请使用sigsetjmp()siglongjmp()来保存和恢复信号掩码,因为在Linux中默认情况下不会保存信号掩码,以清除任何挂起的信号。从setjmp()手册中了解到:

POSIX未指定setjmp()是否会保存信号掩码,在System V中不会。默认情况下,Linux/glibc遵循System V行为。如果要可移植地保存和恢复信号掩码,请使用sigsetjmp()和siglongjmp()

注意:我不确定您想要实现什么,但是您的代码看起来应该在一个无限循环中运行,调用longjmp()会将执行恢复为刚从setjmp()返回并永远继续下去。


我只是想了解为什么程序在第二次调用alarm后不像我的输出显示的那样返回? - Jimm
1
信号处理程序会阻塞更多的信号。由于您从未通过正常手段退出信号处理程序,因此永远不会收到第二个信号。siglongjump 将重新启用信号。 - ams
@ams +1 对于解释在 longjmp() 的情况下信号阻塞的说明。 - Jimm
@ams 也许吧,但是假设你能够以某种方式清除(解除阻止)信号,以允许后续信号通过,如果信号掩码没有恢复,那么这并不重要,对吧? - iabdalkader
@mux 如您所见,当 longjmp 返回时,我会重新为 SIGALRM 重新建立信号处理程序。 - Jimm
@Jimm 是的,那就是原因所在。为了避免这种情况,你需要使用 sigsetjmp()siglongjmp() 来恢复信号掩码,这样可以清除待处理的信号。 - iabdalkader

0
根据http://linux.die.net/man/2/pause: pause() 在信号被捕获并信号捕获函数返回时才会返回。
在你的情况下,它永远不会返回,会执行longjmp(长跳出)。

好的,那么情况下,它应该每2秒执行一次longjmp,因为SIGALRM会每2秒触发一次..但这不是观察到的行为。应用程序在第一次longjmp之后什么也不做。 - Jimm
1
@Jimm,当跳转到从未返回的信号处理程序时,信号会被阻塞。您可以通过在setjmp之前获取信号掩码并在之后恢复来获得预期的行为。这样做的安全方式是使用sigsetjmp - zch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接