信号后未捕获异常

Exception not caught after signal

本文关键字:捕获异常 信号      更新时间:2023-10-16

我尝试在退出之前捕获终止信号以写入我的代码以写入重新启动文件。我的解决方案基于这个答案。

#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;
}
}

异常被抛出很好,但是,我的捕获块没有捕获它。程序终止,并出现未捕获的异常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 编译时,有时会捕获异常,但并非一直如此,这使得这更加奇怪。

在信号处理程序中,您几乎无法可靠地执行任何操作。特别是,不能引发异常。问题中的代码(以及它链接到的"答案"(充其量依赖于特定于编译器/操作系统的行为。有关可以在信号处理程序中执行的操作的限制,请参阅此处。

请注意,上面的链接指的是signal,这是标准 C。sigaction不是标准的C,而是POSIX,C++语言定义不会对使用它的程序施加任何要求。

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

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

Linux 内核中用于信号处理的堆栈帧

从链接问题中的讨论来看,在 linux 系统上,他们甚至没有对堆栈帧使用相同的堆栈,并且返回需要跳回到系统函数以恢复原始用户堆栈。

除非操作系统专门设计用于处理异常,否则这将不起作用。

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