当前位置: 首页 > 面试题库 >

信号处理

穆展鹏
2023-03-14
问题内容

我只是在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()

signal()的行为在UNIX版本之间有所不同,并且在历史上在Linux的不同版本中也有所不同。避免使用它:改为使用sigaction(2)。

再往下走:

* 如果将处置设置为函数,则首先将处置重置为SIG_DFL,或者阻止信号(请参见下面的可移植性),然后使用参数signum调用处理程序。如果调用处理程序导致信号被阻塞,则从处理程序返回后,信号将被解除阻塞。

在原来的Unix系统中,被安装的处理程序时,配置为重置为SIG_DFL,丝毫 阻断的输入信号 相同的
类型,然后将其跑处理函数。System V提供了此功能,而Linux内核也是如此。

这意味着,一旦代码在Linux系统上运行,一旦调用了第二个异常,它将直接退出。

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

在BSD上,当调用信号处理程序时,不会重置信号处理,并且在执行处理程序时会阻止传递其他信号实例。

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

那就是为什么一个人应该使用它sigaction()而不应该使用它signal()

现在来一些提示:

处理程序应简短,并迅速返回。如果执行计算并调用其他函数,则可能是做错了什么。信号不能替代事件驱动的框架。

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

更多阅读内容:信号处理程序中的“执行”和“请勿执行”



 类似资料:
  • 阻塞信号是保持该信号并推迟发送,直到阻塞解除,但不会丢失。 结构体sigset_t(信号集合) 其中每一位对应系统支持的一种信号。结构体内部是数组。 函数 函数名 描述 [[sigemptyset sigempty]] 初始化信号集为空集 [[sigfillset sigfillset]] 初始化信号集包含全部信号 [[sigaddset sigaddset]] 向信号集中添加信号 [[sigde

  • Linux常用31个信号(1~31)。signal.h中有个常量NSIG定义了信号的个数,其值通常为为64。 编号 信号 编号 信号 编号 信号 1 SIGHUP 2 SIGINT 3 SIGQUIT 4 SIGILL 5 SIGTRAP 6 SIGABRT 7 SIGBUS 8 SIGFPE 9 SIGKILL 10 SIGUSR1 11 SIGSEGV 12 SIGUSR2 13 SIGPIP

  • 信号 信号是一种进程间通信(IPC)机制,主要用于处理异步事件。 不同的Unix衍生版所支持的信号类型并不完全相同。除了支持POSIX规定的信号外,还支持其他信号。 术语解释 术语 解释 生成信号 发生了一个需要引起进程注意的事件而导致信号出现时。也叫发送信号 信号交付 被发送信号的那个进程识别到了信号并采取了适当动作。也叫接收信号 信号句柄 当信号出现时调用进行专门处理的函数。这个函数称为捕获函

  • 有的时候我们希望Go能够智能地处理Unix信号。例如我们希望一个server接收到一个SIGTERM的信号时,能够自动地停止;或者一个命令行工具接收到一个SIGINT信号时,能够停止接收输入。现在我们来看下如何使用channel来处理信号。 package main import "fmt" import "os" import "os/signal" import "syscall" func

  • 信号处理器会监听 Worker 进程和 自定义 进程启动后,自动注册到信号管理器中。 安装 composer require hyperf/signal 发布配置 您可以通过下面的命令来发布默认的配置文件到您的项目中: php bin/hyperf.php vendor:publish hyperf/signal 添加处理器 以下我们监听 Worker 进程的 SIGTERM 信号,当收到信号

  • 信号是由操作系统传给进程的中断,会提早终止一个程序。在 UNIX、LINUX、Mac OS X 或 Windows 系统上,可以通过按 Ctrl+C 产生中断。 有些信号不能被程序捕获,但是下表所列信号可以在程序中捕获,并可以基于信号采取适当的动作。这些信号是定义在 C++ 头文件 <csignal> 中。 信号 描述 SIGABRT 程序的异常终止,如调用 abort。 SIGFPE 错误的算术