2016-08-24 57 views
0

我只是使用函数alarm跳过了getchar,但是有些事情并不顺利,因为它只跳过一次,我无限期地需要它。SIGALRM闹钟只跳过一次getchar

例子:

#include <signal.h> 

int duration = 2; 

main() { 
    cicleProgram(); 
} 

void cicleProgram(){ 

    while(opcion != 'q' && opcion != 'Q'){ 

    signal(SIGALRM, (void*)cicleProgram); 
    alarm(duration); 

    opcion = getchar(); 
    } 
} 

我在做什么错?

+1

'opcion'的文章定义。 – chux

+1

您已将circleProgram设置为SIGALRM的信号处理程序。当引发一个SIGALRM时,操作系统似乎认为你的程序正忙于处理SIGALRM,直到你的信号处理程序返回,所以它不会再向你发送一个。 – immibis

+0

您也可能发生死锁 - 您只能在信号处理程序中使用[异步信号安全](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04)函数。 Page down - 有一系列POSIX要求的异步信号安全功能。在你的实现中,当发送警报信号时,你可能会在'getchar()'中等待输入,导致另一个'circleprogram()'的调用异步启动 - 超出正常程序流程。它尝试调用'getchar()',但原始调用的输入流锁定 - 死锁。 –

回答

0

您使用cicleProgram()作为信号处理程序(尽管有错误的类型 - 这应该采取int参数)。这意味着,除非您键入qQ,否则系统可能会阻止信号,直到第一个信号处理程序返回时才会从信号处理程序返回。所以,你永远不会得到第二个信号 - 它被阻止。

使用单独的信号处理函数。另请参阅What is the difference between sigaction() and signal()?并使用sigaction()优先于signal()

并使用int main(void) - 至少返回类型。即使是旧的(C99)版本的标准也要求,更不用说现行的(C11)标准。我们已进入21世纪;不要在20世纪的C代码!

另请参阅How to avoid using printf() in a signal handler?了解有关在信号处理程序中可以执行的操作的信息。


难道我在添加一些控制,“虽然”,以评估信号报警,避免僵局?

原始代码有多个问题,并不是所有可能的问题都被诊断出来。另外一个问题是,如果闹钟开了,没有什么可以再次设置闹钟,所以程序会一直等到你输入一个字符。

这里是你玩一些实验代码:

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

static int duration = 2; 
static volatile sig_atomic_t alarm_fired = 0; 

static void alarm_handler(int signum) 
{ 
    //signal(SIGALRM, alarm_handler); 
    write(STDOUT_FILENO, "Signalled!\n", 11); 
    alarm_fired = signum; 
    alarm(duration); 
} 

static void cicleProgram(void) 
{ 
    int opcion = 0; 
    while (opcion != 'q' && opcion != 'Q') 
    { 
     signal(SIGALRM, alarm_handler); 
     alarm(duration); 
     if ((opcion = getchar()) == EOF) 
      clearerr(stdin); 
     if (alarm_fired) 
     { 
      alarm_fired = 0; 
      printf("Alarm!\n"); 
     } 
     printf("c = %d\n", opcion); 
    } 
} 

static void actionProgram(void) 
{ 
    struct sigaction sa = { 0 }; 
    sa.sa_handler = alarm_handler; 
    sa.sa_flags = 0; 
    sigfillset(&sa.sa_mask); 
    sigaction(SIGALRM, &sa, 0); 

    int opcion = 0; 
    while (opcion != 'q' && opcion != 'Q') 
    { 
     alarm(duration); 
     if ((opcion = getchar()) == EOF) 
      clearerr(stdin); 
     if (alarm_fired) 
     { 
      alarm_fired = 0; 
      printf("Alarm!\n"); 
     } 
     printf("c = %d\n", opcion); 
    } 
} 

int main(void) 
{ 
    printf("Using signal (q to quit):\n"); 
    cicleProgram(); 
    printf("Using sigaction (q to quit):\n"); 
    actionProgram(); 
    return 0; 
} 

有两个积极作用,每一个循环。第一个是根据您的原始cicleProgram(),但功能已经修改;它不再是信号处理程序。我在Mac OS X(基于BSD)上运行,并且这些系统不要求您重置信号处理函数中的signal()处理程序。第二个函数actionProgram()使用sigaction()而不是signal()。这可能不是必要的,但它可以让你看到一些东西。 sa.sa_flags元素中缺少SA_RESTART表示系统调用会在每次信号关闭时报告它被中断。 signal_handler()中的代码不使用不允许的函数调用。

输出示例(程序名al97):

$ ./al97 
Using signal (q to quit): 
Signalled! 
Signalled! 
Signalled! 
Signalled! 
WonderfulSignalled! 

Alarm! 
c = 87 
c = 111 
c = 110 
c = 100 
c = 101 
c = 114 
c = 102 
c = 117 
c = 108 
c = 10 
Signalled! 
Signalled! 
q 
Alarm! 
c = 113 
Using sigaction (q to quit): 
c = 10 
Signalled! 
Alarm! 
c = -1 
Signalled! 
Alarm! 
c = -1 
Signalled! 
Alarm! 
c = -1 
Signalled! 
Alarm! 
c = -1 
ASignalled! 
Alarm! 
c = -1 
lso workingSignalled! 
Alarm! 
c = -1 

c = 65 
c = 108 
c = 115 
c = 111 
c = 32 
c = 119 
c = 111 
c = 114 
c = 107 
c = 105 
c = 110 
c = 103 
c = 10 
qSignalled! 
Alarm! 
c = -1 

c = 113 
$ 

有在运行一些比较长的停顿,但你可以尝试你的机器上。您可能需要在的alarm_handler()函数中重新包含signal(),并使用actionProgram()的不同处理程序(不像现在使用signal())。

+0

所以我可以在“while”中添加一些控件以评估信号警报并避免死锁? 谢谢! – DAM

+0

@DAM:查看更新的答案 - 玩,享受。 –

+0

非常感谢! 之后我会证明你和我的代码会看到更密切的发生 真的非常感谢 – DAM