C/C++属于较为接近底层的语言,不像Java等“高级”语言,所有异常都能catch住(例如常见的core dumped)异常:
- int first_func()
- {
- int* error_integer = nullptr;
- return *error_integer;
- }
对于异常,首要任务是进行定位,并做对应的修复。但存在一些程序,因种种原因测试不够充分,为了保证程序“不崩溃”,本文介绍几个常见的异常处理方法。
针对SIGSEGV信号处理的异常,需要新增编译选项
-fnon-call-exceptions
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
- #include
- #include
-
-
- /**
- * 省略部分代码
- */
-
-
- 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
- #include
- #include
- #include
-
- 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;
- }