我有一个信号处理片段,但它在我的Mac和虚拟Linux盒子koding.com上出现故障,但在我的办公室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
信号动作&amp;因此,当我第二次按Ctrl + C时它退出程序。有人能解释我为什么吗?
答案 0 :(得分:5)
不允许您调用信号处理程序中的每个函数。
阅读signal(7)。 只能异步信号安全函数(直接或间接)来自信号处理程序,而printf
不是这样的函数。如果你真的想要可靠&#34;打印&#34;来自信号处理程序内部的东西(我不推荐),你只能使用低级write(2)系统调用(它是异步信号安全的)。
所以你已经undefined behavior了。 This解释了为什么它如此糟糕。
建议的方法是在信号处理程序中设置volatile sigatomic_t
标志,并在其外测试它(例如在while
循环中...)。
你忘了打电话给fflush(3)。将printf
格式字符串与\n
结尾可能会更幸运,因为stdout
是行缓冲的!
当然,即使使用printf
,更改信号处理程序中的\n
仍然是UB,但通常它似乎可以正常工作。
以下是您的计划的一致版本....
#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)单个字节 - 在pipe(7)上为你自己设置信号处理程序(你在早期使用pipe(2)设置该管道程序初始化),并在事件循环poll(2)中读取该管道的结尾。
答案 1 :(得分:0)
printf是罪魁祸首,只需在处理程序中使用计数器并打印外部处理程序,它的值将起作用。
使用sigaction而不是signal