由于printf不是可重入的,因此在信号处理程序中使用它并不安全。但是我看过很多使用printf这种方式的示例代码。
printf
所以我的问题是:我们什么时候需要避免printf在信号处理程序中使用,并且有推荐的替代品吗?
您可以使用一些标志变量,在信号处理程序中设置该标志,并printf()在正常操作期间基于main()或程序其他部分中的该标志调用函数。
printf()
printf从信号处理程序中调用所有函数(例如)是不安全的。一种有用的技术是使用信号处理程序设置a flag,然后flag 从主程序中检查它并在需要时打印一条消息。
flag
注意,在下面的示例中,信号处理程序ding()alarm_fired在捕获到SIGALRM时将标志设置为1,并alarm_fired检查主函数值以有条件地正确调用printf。
alarm_fired
static int alarm_fired = 0; void ding(int sig) // can be called asynchronously { alarm_fired = 1; // set flag } int main() { pid_t pid; printf("alarm application starting\n"); pid = fork(); switch(pid) { case -1: /* Failure */ perror("fork failed"); exit(1); case 0: /* child */ sleep(5); kill(getppid(), SIGALRM); exit(0); } /* if we get here we are the parent process */ printf("waiting for alarm to go off\n"); (void) signal(SIGALRM, ding); pause(); if (alarm_fired) // check flag to call printf printf("Ding!\n"); printf("done\n"); exit(0); }
参考:Beginning LinuxProgramming,第4版,在本书中,准确说明了您的代码(所需的内容),第11章:进程和信号,第484页
此外,在编写处理程序函数时需要特别小心,因为它们可以异步调用。也就是说,处理程序可能在程序中的任何地方被意外地调用。如果两个信号在很短的间隔内到达,则一个处理程序可以在另一个处理程序中运行。并且,最好声明为volatile sigatomic_t,始终以原子方式访问此类型,以避免不确定中断对变量的访问。(有关详细信息,请阅读:原子数据访问和信号处理)。
volatile sigatomic_t
阅读定义信号处理程序:了解如何编写可以使用signal()或sigaction()函数建立的信号处理程序功能。手册页 中授权功能的列表,在信号处理程序中调用此功能是安全的。
signal()
sigaction()