简介
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();
} 
使用方式:
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上。
使用进程方法时,可能会有备选方案:为了系统稳定性,会从多个方案中选择稳定的方案进行尝试。
“串行”尝试
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;
} 
                


















