为什么信号处理出现故障?

时间:2015-07-23 13:25:11

标签: c linux bsd signal-handling

我有一个信号处理片段,但它在我的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时它退出程序。有人能解释我为什么吗?

2 个答案:

答案 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