我有以下代码.当我使用gnu extensions(-std=gnu99)编译它时,程序将在结束之前捕获5 SIGINT(我期望).在没有它的情况下编译(-std=c99)在第二个之后结束(并且只输出一行).
我错过了什么?
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
int int_stage = 0;
int got_signal = 0;
void sigint(int parameter)
{
(void)parameter;
got_signal = 1;
int_stage++;
}
int main()
{
signal(SIGINT,sigint);
while(1)
{
if (got_signal)
{
got_signal = 0;
puts("still alive");
if (int_stage >= 5) exit(1);
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用sigaction(2)而不是signal(2).
Linux手册页特别在"可移植性"部分中有这个:
在原始UNIX系统中,当通过传递信号调用使用signal()建立的处理程序时,信号的处置将重置为SIG_DFL,并且系统不会阻止信号的其他实例的传递.System V还为signal()提供了这些语义.这很糟糕,因为信号可能会在处理程序有机会重新建立之前再次传递.此外,相同信号的快速传递可能导致处理程序的递归调用.
BSD通过改变信号处理的语义改进了这种情况(但遗憾的是,在使用signal()建立处理程序时,默默地改变了语义).在BSD上,当调用信号处理程序时,不重置信号处理,并且在处理程序执行时阻止信号的其他实例被传递.
Linux上的情况如下:
内核的signal()系统调用提供了System V语义.
默认情况下,在glibc 2及更高版本中,signal()包装器函数不会调用内核系统调用.相反,它使用提供BSD语义的标志来调用sigaction(2).只要定义了_BSD_SOURCE功能测试宏,就会提供此默认行为.默认情况下,定义_BSD_SOURCE; 如果定义_GNU_SOURCE,它也是隐式定义的,当然可以明确定义.
在glibc 2及更高版本中,如果未定义_BSD_SOURCE功能测试宏,则signal()提供System V语义.(如果在其标准模式之一(-std = xxx或-ansi)中调用gcc(1)或定义各种其他功能测试宏(如_POSIX_SOURCE,_XOPEN_SOURCE或_SVID_SOURCE),则不提供_BSD_SOURCE的默认隐式定义;请参阅feature_test_macros (7).)
使用std=gnu99,您将获得BSD语义.使用-std=c99,您将获得System V语义.因此,在一种情况下(BSD)"重新安装"信号处理程序,并且信号处理在另一种情况下(系统V)重置回SIG_DFL.