简介
C/C++属于较为接近底层的语言,不像Java等“高级”语言,所有异常都能catch住(例如常见的core dumped)异常:
int first_func()
{
int* error_integer = nullptr;
return *error_integer;
}
对于异常,首要任务是进行定位,并做对应的修复。但存在一些程序,因种种原因测试不够充分,为了保证程序“不崩溃”,本文介绍几个常见的异常处理方法。
Trap SIGSEGV 使用 try/catch
针对SIGSEGV信号处理的异常,需要新增编译选项
-fnon-call-exceptions
CMakeList:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fnon-call-exceptions")
定义SegmentationFaultException:
class SegFaultException : public std::exception {
public:
const char* what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override
{
return "segmentation fault";
}
~SegFaultException() override = default;
};
void throw_segmentation_fault_exception(int)
{
throw SegFaultException();
}
使用方式:
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
/**
* 省略部分代码
*/
int main()
{
signal(SIGSEGV, throw_segmentation_fault_exception);
try {
first_func();
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
使用这种方式后可以捕获空指针异常,但整个程序会变得不够安全:有些原本不会抛出异常的场景也会抛出异常,这可能会导致一些问题,例如抛出异常后造成内存泄漏。
除了简单的Demo外,有专门的开源代码Trap底层异常:
https://code.google.com/archive/p/segvcatch/https://code.google.com/archive/p/segvcatch/
“保护进程”
思路是由一个主进程保证安全,fork子进程处理工作。如果子进程异常,不影响主流程。这类方法主要是需要应用在多核CPU上。
使用进程方法时,可能会有备选方案:为了系统稳定性,会从多个方案中选择稳定的方案进行尝试。
“串行”尝试
#include <cstdlib>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
pid_t pid, w;
int w_status;
for (int attempts = 0; attempts < 2; ++attempts) {
pid = fork();
/**
* exit if fork fail
*/
// 子进程
if (pid == 0) {
attempts == 0 ? first_func() : second_func();
exit(0);
}
w = waitpid(pid, &w_status, WUNTRACED | WCONTINUED);
}
printf("parent done. \n");
return 0;
}
如果需要使用waitpid的返回值和获取对应子进程的状态,可以参考:
https://www.codingdict.com/questions/45424https://www.codingdict.com/questions/45424
“并行”尝试
同“串行”比较相似:
int main()
{
pid_t pids[2];
for (int attempts = 0; attempts < 2; ++attempts) {
pid_t pid = fork();
if (pid == 0) {
attempts == 0 ? first_func() : second_func();
exit(0);
}
pids[attempts] = pid;
}
for (auto& p: pids) {
waitpid(p, nullptr, WUNTRACED | WCONTINUED);
}
return 0;
}