如何避免在信号处理程序中使用 printf? [英] How to avoid using printf in a signal handler?

查看:24
本文介绍了如何避免在信号处理程序中使用 printf?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为 printf 不是可重入的,所以在信号处理程序中使用它是不安全的.但是我已经看到很多使用 printf 这种方式的示例代码.

Since printf is not reentrant, it's not supposed to be safe to use it in a signal handler. But I've seen lots of example codes that uses printf this way.

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

So my question is: when do we need to avoid using printf in a signal handler, and is there a recommended replacement?

推荐答案

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

You can use some flag variable, set that flag inside signal handler, and based on that flag call printf() function in main() or other part of program during normal operation.

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

It is not safe to call all functions, such as printf, from within a signal handler. A useful technique is to use a signal handler to set a flag and then check that flag from the main program and print a message if required.

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

Notice in example below, signal handler ding() set a flag alarm_fired to 1 as SIGALRM caught and in main function alarm_fired value is examined to conditionally call printf correctly.

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
");
    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
");
    (void) signal(SIGALRM, ding);
    pause();
    if (alarm_fired)  // check flag to call printf
      printf("Ding!
");
    printf("done
");
    exit(0);
}

参考:入门 Linux 编程,第 4 版,在这本书中准确地解释了您的代码(您想要什么),第 11 章:进程和信号,第 484 页

Reference: Beginning Linux Programming, 4th Edition, In this book exactly your code is explained (what you want), Chapter 11: Processes and Signals, page 484

此外,在编写处理程序函数时需要特别小心,因为它们可以被异步调用.也就是说,处理程序可能会在程序中的任何时候被不可预测地调用.如果两个信号在很短的时间间隔内到达,一个处理程序可以在另一个处理程序中运行.并且声明 volatile sigatomic_t 被认为是更好的做法,这种类型总是以原子方式访问,避免中断访问变量的不确定性.(阅读:原子数据访问和信号处理 详细解释).

Additionally, you need to take special care in writing handler functions because they can be called asynchronously. That is, a handler might be called at any point in the program, unpredictably. If two signals arrive during a very short interval, one handler can run within another. And It is considered better practice to declare volatile sigatomic_t, this type are always accessed atomically, avoid uncertainty about interrupting access to a variable. (read: Atomic Data Access and Signal Handling for detail expiation).

阅读定义信号处理程序 :学习如何编写一个信号处理函数,该函数可以用 signal()sigaction() 函数建立.
手册页中的授权函数列表,在signal内部调用这个函数处理程序是安全的.

Read Defining Signal Handlers :to learn how to write a signal handler function that can be established with the signal() or sigaction() functions.
List of authorized functions in manual page, calling this function inside signal handler is safe.

这篇关于如何避免在信号处理程序中使用 printf?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆