在处理函数

时间:2017-06-14 09:28:28

标签: event-handling signals handler

我从GNU库中获取了这个例子。我想知道为什么他们调用signal()函数两次,第一次在main()中设置信号处理程序,第二次在处理函数本身内。

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

/* This flag controls termination of the main loop. */
volatile sig_atomic_t keep_going = 1;

/* The signal handler just clears the flag and re-enables itself. */
void
catch_alarm (int sig)
{
  keep_going = 0;
  signal (sig, catch_alarm);
}

void
do_stuff (void)
{
  puts ("Doing stuff while waiting for alarm....");
}

int
main (void)
{
  /* Establish a handler for SIGALRM signals. */
  signal (SIGALRM, catch_alarm);

  /* Set an alarm to go off in a little while. */
  alarm (2);

  /* Check the flag once in a while to see when to quit. */
  while (keep_going)
    do_stuff ();

  return EXIT_SUCCESS;
}

现在我的代码......

 void createTimer(long freq_nanosec)
 {
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec timerint;
    struct sigaction saction;

    /* Establish handler for timer signal */
    saction.sa_flags = 0;
    saction.sa_handler = OnTimer;
    sigemptyset(&saction.sa_mask);
    sigaddset (&saction.sa_mask, SIGIO);
    if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
    else printf("OnTimer handler created\n");

    /* Create real time signal */
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGALRM;
    sev.sigev_value.sival_ptr = &timerid;
    if (timer_create(CLOCKID, &sev, &timerid) == -1) error("timer_create");
    else printf("timer ID is 0x%lx\n", (long) timerid);

    /* Arm the timer */
    timerint.it_value.tv_sec = timerint.it_interval.tv_sec =
        freq_nanosec / 1000000000;
    timerint.it_value.tv_nsec = timerint.it_interval.tv_nsec = 
        freq_nanosec % 1000000000;
    if (timer_settime(timerid, 0, &timerint, NULL) == -1)                     
               error("timer_settime");
    else printf("Timer armed\n");
}

2 个答案:

答案 0 :(得分:0)

signal的{​​{3}},我们看到信号到达时:

  

首先将处置重置为SIG_DFL,或者阻止信号(参见下面的可移植性),然后使用参数signum调用处理程序。

因此,在信号到达后,其他信号将恢复为默认行为。在您的示例代码中,处理程序选择重新设置信号处理程序,以便以与第一个相同的方式处理更多信号。

在您找到的代码中的函数catch_alarm的注释中注明了这一点。

答案 1 :(得分:0)

signal有两个流行版本,它们在调用处理程序时是否将信号的处置重置为默认值,以及在处理程序执行期间信号是否被阻塞方面不同。 / p>

standard表示这两种行为是实现定义的。第一个代码示例

void
catch_alarm (int sig)
{
  keep_going = 0;
  signal (sig, catch_alarm);
}

假设在调用处理程序时,实现可能会将信号处置重置为默认值。这就像在处理程序的第一行中调用signal(sig, SIG_DFL)一样。您几乎从不想要这样,因为下次有SIGALRM信号进入时,默认操作是程序被杀死。因此处理程序调用{​​{1}}来重新建立自己作为处理程序。

您的第二个代码示例

signal(sig, catch_alarm)

使用sigaction,这通常比saction.sa_flags = 0; saction.sa_handler = OnTimer; sigemptyset(&saction.sa_mask); sigaddset (&saction.sa_mask, SIGIO); if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction"); 更受欢迎,因为您可以准确指定所需的行为。标准说

  

新应用程序应该使用sigaction()而不是signal()。

signal开启.sa_flags标志时,处理程序启动时信号的处置将重置为默认值,就像({1}}的(一个版本)一样。

但是在你的情况下,那个标志是关闭的,因为你将SA_RESETHAND设置为0,所以你不需要编写任何代码来重新建立处理程序。