一尘不染

如何避免在信号处理程序中使用printf?

linux

由于printf不是可重入的,因此在信号处理程序中使用它并不安全。但是我看过很多使用printf这种方式的示例代码。

所以我的问题是:我们什么时候需要避免printf在信号处理程序中使用,并且有推荐的替代品吗?


阅读 431

收藏
2020-06-02

共1个答案

一尘不染

您可以使用一些标志变量,在信号处理程序中设置该标志,并printf()在正常操作期间基于main()或程序其他部分中的该标志调用函数。

printf从信号处理程序中调用所有函数(例如)是不安全的。一种有用的技术是使用信号处理程序设置a flag,然后flag
从主程序中检查它并在需要时打印一条消息。

注意,在下面的示例中,信号处理程序ding()alarm_fired在捕获到SIGALRM时将标志设置为1,并alarm_fired检查主函数值以有条件地正确调用printf。

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,始终以原子方式访问此类型,以避免不确定中断对变量的访问。(有关详细信息,请阅读:原子数据访问和信号处理)。

阅读定义信号处理程序:了解如何编写可以使用signal()sigaction()函数建立的信号处理程序功能。手册页
中授权功能的列表,在信号处理程序中调用此功能是安全的。

2020-06-02