子进程异常 与 主进程异常

在线程中抛出的异常默认不会自动传递到主线程(或父线程)。如果子线程中未捕获异常,程序会直接终止(调用 std::terminate())。若需在线程间传递异常,需手动捕获并处理。以下是具体分析和解决方案:


1. 默认行为:异常不跨线程传递

问题示例

#include <thread>
#include <iostream>

void thread_func() {
    throw std::runtime_error("子线程抛出异常");
}

int main() {
    try {
        std::thread t(thread_func);
        t.join();
    } catch (const std::exception& e) {
        std::cout << "捕获到异常: " << e.what() << std::endl;
    }
    return 0;
}

结果:
程序崩溃,调用 std::terminate(),主线程的 catch 块无法捕获子线程的异常。


2. 解决方案:手动捕获并传递异常

方法 1:使用 try-catch 捕获子线程异常

在子线程内部捕获异常,通过共享变量传递错误信息:

#include <thread>
#include <iostream>
#include <exception>
#include <mutex>

std::exception_ptr thread_exception = nullptr;
std::mutex mtx;

void thread_func() {
    try {
        throw std::runtime_error("子线程抛出异常");
    } catch (...) {
        std::lock_guard<std::mutex> lock(mtx);
        thread_exception = std::current_exception(); // 捕获异常指针
    }
}

int main() {
    std::thread t(thread_func);
    t.join();

    if (thread_exception) {
        try {
            std::rethrow_exception(thread_exception); // 重新抛出异常
        } catch (const std::exception& e) {
            std::cout << "主线程捕获到异常: " << e.what() << std::endl;
        }
    }
    return 0;
}

输出

主线程捕获到异常: 子线程抛出异常

方法 2:使用 std::promisestd::future

通过 std::promise 存储异常,主线程通过 std::future 获取:

#include <thread>
#include <iostream>
#include <future>

void thread_func(std::promise<void> prom) {
    try {
        throw std::runtime_error("子线程抛出异常");
    } catch (...) {
        prom.set_exception(std::current_exception()); // 传递异常到 promise
    }
}

int main() {
    std::promise<void> prom;
    std::future<void> fut = prom.get_future();

    std::thread t(thread_func, std::move(prom));
    t.detach(); // 或 t.join()

    try {
        fut.get(); // 触发异常(若子线程有异常)
    } catch (const std::exception& e) {
        std::cout << "主线程捕获到异常: " << e.what() << std::endl;
    }
    return 0;
}

输出

主线程捕获到异常: 子线程抛出异常

3. 最佳实践

  1. 始终在子线程内部捕获异常
    避免未捕获的异常导致程序终止。
  2. 优先使用 std::promise/future
    适用于需要返回值或异常传递的异步任务。
  3. 对不可恢复的异常直接记录日志
    若主线程无法处理子线程的异常(如内存错误),应在子线程中记录日志后退出。

posted @ 2025-04-23 15:30  BlackSnow  阅读(80)  评论(0)    收藏  举报