这里我有一些代码示例:
/* some headers */
…
/****************/
void handler( int signum ){
printf("Signal number: %d received\n", signum);
signal(signum, SIG_DFL);
}
int main( int argc, char* argv[] ){
signal(SIGINT, handler);
while( "no signal was received" ){
printf("another loop round\n");
sleep(3);
}
return EXIT_SUCCESS;
}
我期待我的程序退出,在我的处理程序函数中定义消息,在CTRL + C键盘组合之后,就像它通常发生的那样,但我必须输入两次命令,并且只在我第二次尝试之后停止。我还想问一个关于signal
功能的另一个问题。我发现了很多引用,人们会建议使用sigaction
函数而不是signal
,但是其中一些人说它出于兼容性原因而更好地使用{signal
1}}。你能给我一些关于我应该使用哪些提示的提示吗?提前致谢
答案 0 :(得分:5)
使用此行
signal(SIGINT, handler);
您通过调用handler()
替换了默认行为,即退出程序。这就是为什么程序不会在接收到信号时退出的原因。
handler()
然后调用
signal(signum, SIG_DFL);
重新设置SIGINT
的默认行为,即在(下一次)接收信号时退出程序。
OT:不应该从信号处理程序中调用printf()
(以及其他),在它(以及其他人)不保证异步信号安全。有关这些功能的列表,请参阅man 7 signal
。
答案 1 :(得分:3)
希望它清楚。
答案 2 :(得分:2)
默认情况下,您的程序有一个退出的SIGINT处理程序。您已将其替换为signal(SIGINT, handler);
如果您希望程序在运行处理程序时退出,则需要自己调用exit
。您可以将处理程序修改为:
void handler( int signum ){
printf("Signal number: %d received\n", signum);
exit(1);
}
为避免出现问题,您不应该从信号处理程序中调用printf
,因为printf
不可重入。 glibc documentation给出了问题的描述:
如果函数使用并修改了您提供的对象,则它可能是不可重入的;如果两个调用使用相同的对象,则会发生干扰。 当您使用流进行I / O时会出现这种情况。假设信号处理程序使用fprintf打印消息。假设在传递信号时,程序正在使用相同的流进行fprintf调用。信号处理程序的消息和程序的数据都可能被破坏,因为两个调用都在相同的数据结构上运行 - 流本身。
如果您没有在处理程序中退出程序,那么您的程序将从中断处继续。另一个选项是通过sleep
的返回值检测SIGINT。如果sleep
因为SIGINT之类的信号被提升而提前退出,则可以使用返回值进行检查。 sleep
的{{3}}表示
返回值顶部
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
当sleep返回大于0的值时,你可以修改你的循环以退出,这意味着它被信号提前中断。像这样的东西会起作用:
signal(SIGINT, handler);
while( sleep(3) == 0 ){
printf("another loop round\n");
}
至于您关于signal
和sigaction
- sigaction
的问题是首选方式。关于为什么可以在StackOverflow问题和man page