c++ - 信号处理

标签 c++ c linux macos signals

我只是在 Mac OS X 中玩信号。

为什么在我的信号处理程序完成后,以下代码不会产生 SIGSEGV 的默认行为? 在 Linux 下,代码运行良好。

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void err_crash();

void my_signal_handler (int signal)
{
    fprintf(stderr, "signal == %i\n", signal);
    fflush(stderr);
    err_crash();
}

void err_crash()
{
    static int count= 0;
    if (count)
        signal(SIGSEGV, SIG_DFL);       /* break recursion loop if we recursed */
    count++;

    // one of the two should really crash ;)
    ((void)(*((int volatile *)NULL)));
    *((int *)NULL) = 42;

    abort();                            /* in case we're not crashed yet... */
}

int main ()
{
    signal(SIGSEGV, my_signal_handler);
    err_crash();
    return 0;
}

编辑: 我得到的输出如下:

bonecrusher:devel sw$ g++ signal_problems.cpp -o foo
bonecrusher:devel sw$ ./foo 
signal == 11
^C
bonecrusher:devel sw$

问题是我希望程序在 signal == 11 输出后终止,但它会一直运行,我不得不中断它。

最佳答案

这实际上让我的大脑卡住了几分钟,而在这个时代永远不应该使用 signal() 的原因只会让我更加坚定。

首先,来自 signal() 的手册页

The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.

再往下:

  • If the disposition is set to a function, then first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum. If invocation of the handler caused the signal to be blocked, then the signal is unblocked upon return from the handler.

在最初的 Unix 系统中,当安装处理程序时,配置被重置为 SIG_DFL,阻止相同类型的传入信号,然后它运行处理函数。 System V 提供了这一点,linux 内核也提供了这一点。

也就是说,一旦代码在linux系统上运行,一旦调用第二个异常,就会直接退出。

现在到了有趣的部分。 BSD 试图改善这种行为。再次从手册页:

On BSD, when a signal handler is invoked, the signal disposition is not reset, and further instances of the signal are blocked from being delivered while the handler is executing.

并且由于 mac osx 部分基于 BSD,一旦代码在 mac osx 上运行,一旦调用第二个异常,它将处于pending并等待第一个异常的处理程序导出。但由于您永远不会退出,因此您陷入了僵局。

这就是为什么应该使用 sigaction() 而不是 signal() 的原因。

现在有一些提示:

handlers 应该很短,并且返回很快。如果您正在执行计算并调用其他函数,则您可能做错了什么。信号不能替代事件驱动框架。

调用非异步安全的函数是不好的。考虑一下如果在调用 fprintf 期间发生异常并且在处理程序内部再次调用 fprintf 会发生什么情况。信号处理程序和程序数据都可能被破坏,因为它们对流本身进行操作。

更多阅读:"Do" and "Don't" inside A Signal Handler

关于c++ - 信号处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4863420/

相关文章:

java - 在我的 Android 应用程序中使用 ffmpeg.c

c++ - 使用 wxWidgets 在 Windows 7 中进行外观和感觉

c++ - 纠错码

c - .byte 在这个 asm 行中是什么意思?

java - 更简单的 Java 守护程序初始化脚本?

linux - 为什么要在保护模式下启用 A20 线?

linux - 为什么 du 或 echo 流水线不起作用?

c++ - 类型的无效操作数 - C++

c++ - 为第三方库 libA.a 包装对 malloc 的调用,但不为 libB.a 包装调用

c - GCC 和 G++ struct packing 的区别?