信号后未捕获异常
Exception not caught after signal
我尝试在我的代码中捕获终止信号,以便在退出前编写一个重启文件。我的解决方案是基于这个answer。
#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 编译时,似乎有时会捕获到异常,但并非总是如此,这让这更奇怪了。
您可以在信号处理程序中可靠地执行的操作非常少。特别是,您不能抛出异常。问题中的代码(以及它 link 的 "answer" )充其量依赖于 compiler/OS-specific 行为。有关在信号处理程序中可以执行的操作的限制,请参阅 this。
注意上面的link指的是signal
,是标准C,sigaction
不是标准C,是POSIX,C++语言定义没有' 对使用它的程序强加任何要求。
在大多数系统上,信号处理程序使用的堆栈帧不是编译器为函数调用定义的标准函数堆栈帧。
因此不支持丢弃 sig 处理程序。
Stack frame for signal handling in the Linux Kernel
从链接问题中的讨论来看,在 linux 系统上,它们甚至没有为堆栈帧使用相同的堆栈,并且返回需要跳回到系统函数以恢复原始用户堆栈。
除非 OS 是专门为处理异常而设计的,否则这是行不通的。
信号处理程序的经验法则是在信号处理程序中做的事情越少越好。设置一个可以被您的普通代码检测到的全局标志,然后在您的普通代码中定期检查该标志以查看信号何时发生。
我尝试在我的代码中捕获终止信号,以便在退出前编写一个重启文件。我的解决方案是基于这个answer。
#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 编译时,似乎有时会捕获到异常,但并非总是如此,这让这更奇怪了。
您可以在信号处理程序中可靠地执行的操作非常少。特别是,您不能抛出异常。问题中的代码(以及它 link 的 "answer" )充其量依赖于 compiler/OS-specific 行为。有关在信号处理程序中可以执行的操作的限制,请参阅 this。
注意上面的link指的是signal
,是标准C,sigaction
不是标准C,是POSIX,C++语言定义没有' 对使用它的程序强加任何要求。
在大多数系统上,信号处理程序使用的堆栈帧不是编译器为函数调用定义的标准函数堆栈帧。
因此不支持丢弃 sig 处理程序。
Stack frame for signal handling in the Linux Kernel
从链接问题中的讨论来看,在 linux 系统上,它们甚至没有为堆栈帧使用相同的堆栈,并且返回需要跳回到系统函数以恢复原始用户堆栈。
除非 OS 是专门为处理异常而设计的,否则这是行不通的。
信号处理程序的经验法则是在信号处理程序中做的事情越少越好。设置一个可以被您的普通代码检测到的全局标志,然后在您的普通代码中定期检查该标志以查看信号何时发生。