我从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");
}
答案 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,所以你不需要编写任何代码来重新建立处理程序。