鉴于此代码:
HandleRequestAsync()
使用以下选项使用#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigint_handler(int h)
{
printf("Hey! I caught a SIGINT! :)\n");
}
int main()
{
struct sigaction act;
act.sa_handler = &sigint_handler;
if (0 != sigaction(SIGINT, &act, NULL)) {
perror("unable to setup the SIGINT handler!\n");
return 1;
}
while(1) { }
return 0;
}
(内核gcc 7.2.0
)进行编译:{{1}}。
第一个信号总是被捕获,但有时候,第二个信号没有被捕获,有时它是。
我在处理过程中发现4.13.12
时遇到了这个错误。启动。
我错过了捕获所有信号的内容?
答案 0 :(得分:2)
在Martin James中观察到comment:
您的SIGINT处理程序只有一行 - 对非同步信号安全的函数的调用:(
稍后,我observed:
您不知道
struct sigaction
中的其他字段设置为什么,因为您没有初始化act
。如果将记录的字段设置为已知值,则可能会获得更好的行为。您可以在POSIX信号处理程序中使用write()
(不是在标准C中,但幸运的是您没有使用标准C)。您不应该使用printf()
,但在此上下文中不太可能造成任何麻烦。write()
的一个小优点 - 无需担心应用程序级缓冲。
问题How to avoid using printf()
in a signal handler讨论了可以在信号处理程序中使用哪些函数。 请注意,(这对于POSIX 2008来说是准确的.POSIX 2016的一个变化是已经添加了许多信号安全例程。 Signal Concepts中的列表,包括<string.h>
标题中的函数(例如strlen()
和strchr()
)未列在异步信号安全的函数中。我觉得这个遗漏令人费解,但这就是POSIX(2008及更早版本)所说的。strlen()
和strchr()
- 这对我来说很有意义。)
我改编了你的代码:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static void sigint_handler(int h)
{
char message[] = "Hey! I caught a SIGINT x! :\n";
char *x = message;
while (*x != 'x' && *x != '\0')
x++;
if (*x != '\0')
*x = (h % 10) + '0';
write(1, message, sizeof(message) - 1);
}
int main(void)
{
struct sigaction act = { 0 };
act.sa_handler = &sigint_handler;
if (0 != sigaction(SIGINT, &act, NULL))
{
perror("Unable to setup the SIGINT handler!\n");
return 1;
}
while (1)
{
printf("Pausing for a moment...\n");
pause();
printf("You interrupted my dozing\n");
}
return 0;
}
代码使用pause()
而不是在忙循环中旋转。这是一个不寻常的系统调用;它永远不会正常返回(exec*()
函数族也不会正常返回。)
我使用严格的警告选项进行编译:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes sig13.c -o sig13
$
如果我没有使用h
(信号处理程序的参数),代码将无法编译,所以我使用它。代码避免使用字符串处理函数(char *x = strchr(message, 'x'); if (x != 0) *x = (h % 10) + '0';
会更清楚)。该函数是static
,因为它不会在此文件之外使用 - 所以没有标题来声明它。
执行时(在Mac上运行macOS High Sierra 10.13.2,使用GCC 7.2.0),它会产生如下输出:
$ ./sig13
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^\Quit: 3
$
这方面的主要道德是“确保你的变量被正确初始化”。次要道德是确保你的信号处理程序是干净的。
答案 1 :(得分:0)
我的代码存在两个问题,首先,正如@MartinJames和@ j31d0所提到的,printf
函数不是async-signal-safe,所以它不能在信号处理程序中使用。它可以很容易地被write
系统调用替换,它是async-signal-safe:
char message[255] = "Hey! I caught a SIGINT :)\n";
write(1, message, 255);
其次,变量act
没有正确初始化(正如@JonathanLeffler所提到的):
sigset_t mask;
struct sigaction act;
sigemptyset(&mask);
act.sa_handler = &sigint_handler;
act.sa_mask = mask;
act.sa_flags = 0;
最后,工作代码如下:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigint_handler(int h)
{
char message[255] = "Hey! I caught a SIGINT :)\n";
write(1, message, 255);
}
int main()
{
sigset_t mask;
struct sigaction act;
sigemptyset(&mask);
act.sa_handler = &sigint_handler;
act.sa_mask = mask;
act.sa_flags = 0;
if (0 != sigaction(SIGINT, &act, NULL)) {
perror("unable to setup the SIGINT handler!\n");
return 1;
}
while(1) { }
return 0;
}
希望这有帮助!