SIGALRM警报只跳过getchar一次

时间:2016-08-24 04:16:29

标签: c

我只是使用函数alarm跳过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 个答案:

答案 0 :(得分: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?,了解有关在信号处理程序中可以执行的操作的信息。

  

我可以在那个&#34;中添加一些控件吗?为了评估信号警报并避免死锁?

原始代码存在多个问题,并未诊断出所有可能的问题。另一个问题是,如果发出警报,则没有任何内容可以再次设置警报,因此程序会等到您输入字符为止。

以下是您玩的一些实验性代码:

#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_RESTART元素中缺少sa.sa_flags表示read()系统调用报告每次信号关闭时它都被中断。 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
$

跑步中有一些相当长的停顿,但你可以在你的机器上进行试验。您可能需要在signal()的{​​{1}}函数中重新包含alarm_handler(),并使用不同的处理程序(不会像现在一样使用cicleProgram()signal() 1}}。