Linux C/C++异常处理方法

简介

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值