C 使用kill函数的递归信号调用

C 使用kill函数的递归信号调用,c,signals,C,Signals,我现在正在学习计算机系统中的信号,我遇到了一个问题。下面给出了一个代码 int i = 0; void handler(int s) { if(!i) kill(getpid(), SIGINT); i++; } int main() { signal(SIGINT, handler); kill(getpid(), SIGINT); printf("%d\n", i); return 0; } 解决方案说可能的输出应该是0、1或2。我知道这些都是可能的,但为什么不是

我现在正在学习计算机系统中的信号,我遇到了一个问题。下面给出了一个代码

int i = 0;
void handler(int s) {
  if(!i) kill(getpid(), SIGINT);
  i++;
}

int main() {
  signal(SIGINT, handler);
  kill(getpid(), SIGINT);
  printf("%d\n", i);
  return 0;
}
解决方案说可能的输出应该是0、1或2。我知道这些都是可能的,但为什么不是3,4或其他


例如,我们在main函数中发送SIGINT。处理程序获取SIGINT信号,并将SIGINT作为零发送。在进入增量代码之前,处理程序可能能够监听SIGINT信号并再次发送SIGINT信号,因为它在增量代码(i=0)之前执行—循环一次,循环一次—它可能打印出3、4、5甚至更大的数字。

过去,关于信号如何工作的很多细节都发生了变化。 例如,在最早的变体中,当调用处理程序时,信号处理恢复为默认,处理程序必须重新建立自身。在这种情况下,从处理程序发送信号将终止进程

目前,通常情况下,当为特定信号调用处理程序时,该信号被阻塞。这意味着此时不会调用处理程序,但在信号解除阻塞时会调用它。由于没有关于信号发送频率的记忆,其中一些可能会“丢失”

见POSIX, ,
而且。

这是因为信号通常在传输时被阻塞。因此,在您的示例中,
处理程序
中的
kill
在该位置不起作用。必须等待处理程序返回,才能再次捕获信号

理论上,您可以获得0,因为在发送信号时它是未指定的。因此,您可能会将信号放入main中,并在发送之前执行
printf

您可以得到1,因为一般情况下,信号传递发生在系统调用结束或quantum开始或结束时。因此,在您的情况下,在发送信号之后,您将返回到用户空间并发送信号,这将产生处理程序的执行,递增
i
,然后返回到正常的执行流,然后打印

您可以使用2,因为当从处理程序返回时,信号将被取消阻止,然后第二次传递。这是更常见的情况

您不能有超过2个,因为您为此设置了条件。当
i=0
您不会再次抛出该信号,因此抛出次数不能超过2次


注意这里没有“递归”…

除非您有一些生成额外信号的外部代码,否则此过程只生成2个信号。如果您正在学习信号,请不要学习
信号,而是学习。正如下面的答案所表明的,前者并非在所有平台上都具有一致的语义。后者确实如此,而且重要的是IMHO迫使您指定您想要的信号行为类型。