您使用cicleProgram()
作为信号处理程序(尽管有错误的类型 - 这应该采取int
参数)。这意味着,除非您键入q
或Q
,否则系统可能会阻止信号,直到第一个信号处理程序返回时才会从信号处理程序返回。所以,你永远不会得到第二个信号 - 它被阻止。
使用单独的信号处理函数。另请参阅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()
)。
'opcion'的文章定义。 – chux
您已将circleProgram设置为SIGALRM的信号处理程序。当引发一个SIGALRM时,操作系统似乎认为你的程序正忙于处理SIGALRM,直到你的信号处理程序返回,所以它不会再向你发送一个。 – immibis
您也可能发生死锁 - 您只能在信号处理程序中使用[异步信号安全](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04)函数。 Page down - 有一系列POSIX要求的异步信号安全功能。在你的实现中,当发送警报信号时,你可能会在'getchar()'中等待输入,导致另一个'circleprogram()'的调用异步启动 - 超出正常程序流程。它尝试调用'getchar()',但原始调用的输入流锁定 - 死锁。 –