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

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) 该管道的读取端。