为什么信号处理出现故障?
Why signal handling is malfunctioning?
我有一个信号处理片段,但它在我的 Mac 和 koding.com 的虚拟 Linux 盒子上出现了某种故障,但在我的办公室 Linux PC 上它正在工作..谁能告诉我为什么..
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void my_isr(int n){
printf("Hello World");
signal(SIGINT, SIG_DFL);
}
int main(){
signal(SIGINT, my_isr);
printf("pid = %d\n", getpid());
while(1);
return 0;
}
当我按下 Ctrl+C 时,它不是第一次打印 Hello World
,而是重新修改 SIGINT
信号操作,因此当我按下 Ctrl 时它正在退出程序+C 第二次。有人可以解释一下为什么吗?
printf 是罪魁祸首,只需在处理程序中使用计数器并在处理程序外部打印其值即可。
使用 sigaction 代替信号
您不能调用信号处理程序中的每个函数。
读取 signal(7). Only async signal safe functions can be called (directly or indirectly) from a signal handler, and printf
is not such a function. If you really want to reliably "print" something from inside a signal handler (which I don't recommend), you can only use the low-level write(2) 系统调用(它是异步信号安全的)。
所以你 undefined behavior. This 解释了为什么它如此 糟糕 。
推荐的方法是在你的信号处理程序中设置一个 volatile sigatomic_t
标志,并在外部 测试它(例如在你的 while
循环中...)。
你忘了打电话给 fflush(3)。以 \n
结束 printf
格式字符串可能会更幸运,因为 stdout
是行缓冲的!
当然,在信号处理程序中更改 printf
仍然是 UB,即使使用 \n
,但通常它似乎可以工作。
这是您程序的符合标准的版本....
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
volatile sig_atomic_t got_signal;
void my_sigint_handler (int signum) {
if (signum == SIGINT) // this is always true!
got_signal = 1;
#define INTERRUPT_MESSAGE "Interrupted!\n"
write(STDOUT_FILENO, INTERRUPT_MESSAGE, strlen(INTERRUPT_MESSAGE));
};
int main(int argc, char**argv) {
struct sigaction act_int;
memset (&act_int, 0, sizeof(act_int));
act_int.sa_handler = my_sigint_handler;
if (sigaction(SIGINT, &act_int, NULL)) {
perror("sigaction"); exit(EXIT_FAILURE);
};
printf ("start %s pid %d\n", argv[0], (int)getpid());
while (!got_signal) {
};
printf ("ended %s after signal\n", argv[0]);
return 0;
}
一个有用的(也是允许的)技巧可能是 write(2) a single byte -inside your signal handler- on a pipe(7) to self (you set up that pipe using pipe(2) early at program initialization), and in your event loop poll(2) 该管道的读取端。
我有一个信号处理片段,但它在我的 Mac 和 koding.com 的虚拟 Linux 盒子上出现了某种故障,但在我的办公室 Linux PC 上它正在工作..谁能告诉我为什么..
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void my_isr(int n){
printf("Hello World");
signal(SIGINT, SIG_DFL);
}
int main(){
signal(SIGINT, my_isr);
printf("pid = %d\n", getpid());
while(1);
return 0;
}
当我按下 Ctrl+C 时,它不是第一次打印 Hello World
,而是重新修改 SIGINT
信号操作,因此当我按下 Ctrl 时它正在退出程序+C 第二次。有人可以解释一下为什么吗?
printf 是罪魁祸首,只需在处理程序中使用计数器并在处理程序外部打印其值即可。
使用 sigaction 代替信号
您不能调用信号处理程序中的每个函数。
读取 signal(7). Only async signal safe functions can be called (directly or indirectly) from a signal handler, and printf
is not such a function. If you really want to reliably "print" something from inside a signal handler (which I don't recommend), you can only use the low-level write(2) 系统调用(它是异步信号安全的)。
所以你 undefined behavior. This 解释了为什么它如此 糟糕 。
推荐的方法是在你的信号处理程序中设置一个 volatile sigatomic_t
标志,并在外部 测试它(例如在你的 while
循环中...)。
你忘了打电话给 fflush(3)。以 \n
结束 printf
格式字符串可能会更幸运,因为 stdout
是行缓冲的!
当然,在信号处理程序中更改 printf
仍然是 UB,即使使用 \n
,但通常它似乎可以工作。
这是您程序的符合标准的版本....
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
volatile sig_atomic_t got_signal;
void my_sigint_handler (int signum) {
if (signum == SIGINT) // this is always true!
got_signal = 1;
#define INTERRUPT_MESSAGE "Interrupted!\n"
write(STDOUT_FILENO, INTERRUPT_MESSAGE, strlen(INTERRUPT_MESSAGE));
};
int main(int argc, char**argv) {
struct sigaction act_int;
memset (&act_int, 0, sizeof(act_int));
act_int.sa_handler = my_sigint_handler;
if (sigaction(SIGINT, &act_int, NULL)) {
perror("sigaction"); exit(EXIT_FAILURE);
};
printf ("start %s pid %d\n", argv[0], (int)getpid());
while (!got_signal) {
};
printf ("ended %s after signal\n", argv[0]);
return 0;
}
一个有用的(也是允许的)技巧可能是 write(2) a single byte -inside your signal handler- on a pipe(7) to self (you set up that pipe using pipe(2) early at program initialization), and in your event loop poll(2) 该管道的读取端。