SIGINT 只捕获了一次
SIGINT caught only one time
鉴于此代码:
#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
(内核 4.13.12
)编译:-Wall -pedantic -ansi -std=gnu11
.
第一个信号总是被捕获,但有时第二个信号捕获不到,有时捕获到。
我在进程启动时发送垃圾邮件 Ctrl-C
时遇到了这个错误。
我错过了什么来捕获所有信号?
我的代码有两个问题,首先,正如@MartinJames 和@j31d0 所提到的,printf
函数不是 async-signal-safe,因此不能在信号处理程序。它可以很容易地被异步信号安全的 write
系统调用替换:
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;
}
希望对您有所帮助!
作为Martin James observed in a :
Your SIGINT handler has only one line - a call to a function that is not async-signal safe:(
稍后,我 :
You've no idea what the other fields in the struct sigaction
are set to because you didn't initialize act
. Maybe you will get better behaviour if you set the documented fields to known values. You can use write()
in a POSIX signal handler (not in standard C, but fortunately you're not using standard C). You shouldn't use printf()
, though in this context it is unlikely to cause any trouble. One minor advantage of write()
— there's no application level buffering to worry about.
问题 How to avoid using printf()
in a signal handler discusses which functions can be used in a signal handler. Note that the functions from the <string.h>
header such as strlen()
and strchr()
are not listed amongst those that are async-signal safe. I find that omission puzzling, but that's what POSIX (2008 and earlier) says. (This was accurate for POSIX 2008. One of the changes in POSIX 2016 is that a number of signal-safe routines have been added to the list in Signal Concepts,包括 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 != '[=10=]')
x++;
if (*x != '[=10=]')
*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()
而不是在一个繁忙的循环中旋转。这是一个不寻常的系统调用;它通常不会 return(exec*()
函数族通常也不会 return)。
我使用严格的警告选项进行编译:
$ 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
$
主要寓意是"make sure your variables are properly initialized"。次要道德是确保您的信号处理程序是干净的。
鉴于此代码:
#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
(内核 4.13.12
)编译:-Wall -pedantic -ansi -std=gnu11
.
第一个信号总是被捕获,但有时第二个信号捕获不到,有时捕获到。
我在进程启动时发送垃圾邮件 Ctrl-C
时遇到了这个错误。
我错过了什么来捕获所有信号?
我的代码有两个问题,首先,正如@MartinJames 和@j31d0 所提到的,printf
函数不是 async-signal-safe,因此不能在信号处理程序。它可以很容易地被异步信号安全的 write
系统调用替换:
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;
}
希望对您有所帮助!
作为Martin James observed in a
Your SIGINT handler has only one line - a call to a function that is not async-signal safe:(
稍后,我
You've no idea what the other fields in the
struct sigaction
are set to because you didn't initializeact
. Maybe you will get better behaviour if you set the documented fields to known values. You can usewrite()
in a POSIX signal handler (not in standard C, but fortunately you're not using standard C). You shouldn't useprintf()
, though in this context it is unlikely to cause any trouble. One minor advantage ofwrite()
— there's no application level buffering to worry about.
问题 How to avoid using printf()
in a signal handler discusses which functions can be used in a signal handler. Note that the functions from the (This was accurate for POSIX 2008. One of the changes in POSIX 2016 is that a number of signal-safe routines have been added to the list in Signal Concepts,包括 <string.h>
header such as strlen()
and strchr()
are not listed amongst those that are async-signal safe. I find that omission puzzling, but that's what POSIX (2008 and earlier) says.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 != '[=10=]')
x++;
if (*x != '[=10=]')
*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()
而不是在一个繁忙的循环中旋转。这是一个不寻常的系统调用;它通常不会 return(exec*()
函数族通常也不会 return)。
我使用严格的警告选项进行编译:
$ 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
$
主要寓意是"make sure your variables are properly initialized"。次要道德是确保您的信号处理程序是干净的。