我有一个信号处理片段,但它在我的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 = %dn", getpid());
while(1);
return 0;
}
当我按Ctrl+C时,它不是第一次打印Hello World
,而是重新修改SIGINT
信号动作&因此,当我第二次按Ctrl+C时,它正在退出程序。有人能告诉我为什么吗?
不允许调用信号处理程序中的每个函数。
阅读(7)信号。只有异步信号安全函数可以(直接或间接)从信号处理程序调用,而printf
不是这样的函数。如果你真的想可靠地从信号处理程序中"打印"一些东西(我不推荐),你只能使用低级的write(2)系统调用(它是异步信号安全的)。
所以你有未定义行为。这就解释了为什么这么糟糕
建议的方法是在信号处理程序中设置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 %dn", argv[0], (int)getpid());
while (!got_signal) {
};
printf ("ended %s after signaln", argv[0]);
return 0;
}
一个有用的(并且允许的)技巧可以是在管道(7)上写(2)一个单字节-在你的信号处理程序中-到self(你在程序初始化时使用pipe(2)设置该管道),并在事件循环poll(2)中该管道的读端。
printf是罪魁祸首,只要在处理程序中使用counter并在处理程序外部打印其值就可以了。
使用sigaction代替signal