我有以下代码。当我使用gnu扩展(-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;
}
答案 0 :(得分:6)
使用sigaction(2)
而不是signal(2)
。
Linux手册页特别在“可移植性”部分中有这个:
在原始UNIX系统中,当使用signal()建立的处理程序被调用时 传递信号,信号的处置将重置为SIG_DFL,系统也会 不阻止传递信号的其他实例。 System V还提供了这些语义 信号()。这很糟糕,因为信号可能会在处理程序有机会之前再次传递 重建自己。此外,快速传递相同信号可能导致递归 调用处理程序。
BSD通过改变信号处理的语义改进了这种情况(但不幸的是, 在使用signal()建立处理程序时,默默地改变了语义。在BSD上,当一个信号 调用处理程序,不重置信号处理,并且信号的其他实例是 阻止在处理程序执行时传递。
Linux的情况如下:
内核的signal()系统调用提供了System V语义。
默认情况下,在glibc 2及更高版本中,signal()包装器函数不会调用内核系统 呼叫。相反,它使用提供BSD语义的标志来调用sigaction(2)。这种默认行为 只要定义了_BSD_SOURCE特征测试宏,就会提供ior。默认情况下,_BSD_SOURCE 被定义为;如果定义了_GNU_SOURCE,它也是隐式定义的,当然可以是explic- 它定义了。
在glibc 2及更高版本上,如果未定义_BSD_SOURCE特征测试宏,则signal()提供 系统V语义。 (如果有的话,则不提供_BSD_SOURCE的默认隐式定义 在其标准模式之一(-std = xxx或-ansi)中调用gcc(1)或定义其他各种功能 测试宏,如_POSIX_SOURCE,_XOPEN_SOURCE或_SVID_SOURCE;见feature_test_macros(7)。)
使用std=gnu99
,您将获得BSD语义。使用-std=c99
,您将获得System V语义。因此,在一种情况下(BSD)“重新安装”信号处理程序,并将信号处理重置回另一个(系统V)中的SIG_DFL。
答案 1 :(得分:2)
问题是信号还会重置信号处理机制,你必须将sigint重置为信号处理程序。从手册
在原始UNIX系统中,当使用signal()建立的处理程序通过传递信号来调用时,信号的处置将重置为SIG_DFL,并且系统不会阻止其他实例的传递。信号。 System V还为signal()提供了这些语义。这很糟糕,因为信号可能会在处理程序有机会重新建立之前再次传递。此外,快速传递相同信号可能会导致处理程序的递归调用。
这是如何使用旧的陈旧的signal()调用来完成的。 注意int_stage和got_signal必须是sig_atomic_t。 您也可以只调用异步安全函数,查看here以获取列表。
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
sig_atomic_t int_stage = 0;
sig_atomic_t got_signal = 0;
void sigint(int parameter)
{
(void)parameter;
got_signal = 1;
int_stage++;
}
int main()
{
signal(SIGINT,sigint);
while(1)
{
if (got_signal)
{
signal(SIGINT,sigint);
got_signal = 0;
puts("still alive");
if (int_stage >= 5) exit(1);
}
}
return 0;
}
请考虑使用sigaction或sigwait。
Sigaction实际上具有相同的想法,但重新初始化信号处理程序没有废话。 Sigwait会在收到信号之前停止你的线程。因此,对于sigwait,您可以调用任何函数或处理任何数据。如果你愿意,我可以给你看示例代码。
答案 2 :(得分:0)
我同意Ethan Steinberg - “忙碌的等待”是如此错误......
但问题是你没有重置信号处理程序。 AFAIK,您必须使用任何版本的C来执行此操作(再次调用“signal(SIGINT,sigint)”。