信号未捕获到异常

时间:2018-09-27 14:25:56

标签: c++ exception exception-handling signals

我尝试在我的代码中捕获终止信号以在退出之前编写重启文件。我的解决方案基于此The MDN spec

#include <exception>
#include <csignal>
#include <iostream>


class InterruptException : public std::exception
  {
   public:
    InterruptException(int _s) : signal_(_s) { }
    int signal() const noexcept
    {
      return this->signal_;
    }

   private:
    int signal_;
  };

  /// method to throw exception at signal interrupt
  void sig_to_exception(int s)
  {
    throw InterruptException(s);
  }

int main()
{
  // activate signal handling
  struct sigaction sigIntHandler;
  sigIntHandler.sa_handler = sig_to_exception;
  sigemptyset(&sigIntHandler.sa_mask);
  sigIntHandler.sa_flags = 0;
  sigaction(SIGINT, &sigIntHandler, NULL);

  try
  {
    for (std::size_t i = 0; i < 100000000; ++i)
    {
      std::cout  << i << std::endl;
    }
  }
  catch (const InterruptException& e)
  {
    std::cout << "Received signal " << e.signal() << std::endl;
    std::exit(1);
  }
  catch(...)
  {
    std::cout << "Other catch!" << std::endl;
  }
}

可以很好地抛出异常,但是我的catch块无法捕获它。程序以未捕获的异常InterruptException终止。我在MacOS上尝试了clang和gcc。知道为什么无法正确捕获异常吗?

谢谢

使用g ++ 7.3.0编译时的输出:

terminate called after throwing an instance of 'InterruptException'
   what():  std::exception
Abort trap: 6

使用Apple LLVM 9.0.0编译时的输出

libc++abi.dylib: terminating with uncaught exception of type InterruptException: std::exception

PS:似乎当我使用Apple LLVM进行编译时,有时会捕获异常,但并非总是如此,这使它变得更加奇怪。

2 个答案:

答案 0 :(得分:0)

您几乎无法在信号处理程序中可靠地完成操作。特别是,您不能引发异常。问题中的代码(及其链接到的“答案”)充其量取决于编译器/操作系统特定的行为。有关在信号处理程序中可以执行的操作的限制,请参见this

请注意,上面的链接引用的是signal,它是标准C。sigaction不是标准C,它是POSIX,并且C ++语言定义对使用该程序的程序没有任何要求。它。

答案 1 :(得分:0)

在大多数系统上,信号处理程序使用的堆栈帧不是编译器为函数调用定义的标准函数堆栈帧。

因此不支持抛出sig处理程序。

Stack frame for signal handling in the Linux Kernel

在链接的问题中进行的讨论中,在linux系统上,它们甚至没有使用相同的堆栈作为堆栈框架,而返回则需要跳回到系统功能以恢复原始用户堆栈。

除非操作系统是专门为处理异常而设计的,否则它将无法正常工作。

信号处理程序的经验法则是在信号处理程序中执行尽可能少的操作。设置一个普通代码可以检测到的全局标志,然后定期在普通代码中检查该标志,以查看信号何时发生。