You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++多线程异常处理优化:线程抛异常时主线程立即返回

线程异常时主线程立即退出的实现方案

问题背景

现有代码中,主线程创建多个子线程执行计算任务,子线程捕获异常后通过互斥锁同步共享的std::exception_ptr。当前逻辑是主线程必须等待所有子线程完成join后才会检查并抛出异常,需求修改为:只要有任意一个子线程抛出异常,主线程立即返回1,无需等待其他线程执行完毕。

手动修改方案(基于原子变量)

核心思路是用原子变量标记异常状态,主线程循环检查该状态,一旦检测到异常就停止等待并退出;同时子线程在异常发生时标记状态,后续线程可以检测状态提前退出(可选优化)。

修改后的完整代码:

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <stdexcept>
#include <atomic>

class MyClass {
public:
    void run() {
        // 模拟可能抛出异常的工作
        // 比如:if (some_condition) throw std::runtime_error("Simulation failed");
    }
    struct Data {
        double x{0.0};
        int y{0};
    } data;
};

void Thread_function(int i, MyClass myclass, std::atomic<bool>& has_exception, std::exception_ptr& exc, std::mutex& mtx)
{
    // 先检查是否已有异常,有则直接退出
    if (has_exception.load(std::memory_order_relaxed)) {
        return;
    }

    try {
        auto dataCopy = myclass.data;
        dataCopy.x = i + 1;
        dataCopy.y = static_cast<int>((i + 1) * 0.5);
        myclass.data = dataCopy;
        myclass.run();
    } 
    catch (const std::exception& exception)
    {
        // 先标记异常状态(原子操作无需锁)
        has_exception.store(true, std::memory_order_relaxed);
        // 锁保护保存异常指针(仅需一次)
        std::lock_guard<std::mutex> lock(mtx);
        if (!exc) { // 只保存第一个异常
            exc = std::current_exception();
        }
    }
}

int main() {
    const int num_threads = 5;
    std::vector<std::thread> threads;
    std::exception_ptr capturedException;
    std::mutex mtx;
    std::atomic<bool> has_exception{false}; // 原子变量标记异常
    MyClass myClass;

    // 创建线程
    for (int i = 0; i < num_threads; ++i) 
    {
        threads.emplace_back(
            Thread_function, i, myClass, std::ref(has_exception), std::ref(capturedException), std::ref(mtx));
    }

    // 循环检查异常状态,无需等待所有线程完成
    while (!has_exception.load(std::memory_order_relaxed)) {
        // 短暂让出CPU,避免忙等
        std::this_thread::yield();
        // 可选:检查是否所有线程都正常完成了
        bool all_finished = true;
        for (auto& t : threads) {
            if (t.joinable()) {
                all_finished = false;
                break;
            }
        }
        if (all_finished) {
            break;
        }
    }

    // 处理异常:如果有异常则抛出并返回1
    if (has_exception) {
        // 可选:可以join已完成的线程,或detach未完成的(注意资源泄漏风险)
        // 这里简单处理:直接抛出异常,未完成的线程会在程序退出时被终止
        if (capturedException) {
            std::rethrow_exception(capturedException);
        }
        return 1;
    }

    // 所有线程正常完成,join剩余线程
    for (auto& t : threads) {
        if (t.joinable()) {
            t.join();
        }
    }

    return 0;
}

C++标准库便捷实现:std::promise + std::future

C++11及以上的std::promise和std::future可以更简洁地实现这个需求:子线程通过promise设置异常,主线程通过future.get()会立即响应(一旦有异常被设置,get()会直接抛出),无需手动循环检查。

示例代码:

#include <iostream>
#include <thread>
#include <vector>
#include <stdexcept>
#include <future>

class MyClass {
public:
    void run() {
        // 模拟异常
        // throw std::runtime_error("Task failed");
    }
    struct Data {
        double x{0.0};
        int y{0};
    } data;
};

void Thread_function(int i, MyClass myclass, std::promise<void>& prom)
{
    try {
        auto dataCopy = myclass.data;
        dataCopy.x = i + 1;
        dataCopy.y = static_cast<int>((i + 1) * 0.5);
        myclass.data = dataCopy;
        myclass.run();
        prom.set_value(); // 任务正常完成,设置值
    } 
    catch (...)
    {
        prom.set_exception(std::current_exception()); // 设置异常
    }
}

int main() {
    const int num_threads = 5;
    std::vector<std::thread> threads;
    std::vector<std::future<void>> futures;
    MyClass myClass;

    // 创建线程和对应的promise/future
    for (int i = 0; i < num_threads; ++i) 
    {
        std::promise<void> prom;
        futures.push_back(prom.get_future());
        threads.emplace_back(
            Thread_function, i, myClass, std::move(prom));
    }

    // 等待任意一个future完成(或抛出异常)
    for (auto& fut : futures) {
        try {
            fut.get(); // 一旦有子线程设置异常,这里会立即抛出
        } catch (...) {
            // 异常发生,无需等待其他线程,直接返回1
            // 可选:终止其他线程(需要额外的终止机制,比如原子标记)
            return 1;
        }
    }

    // 所有线程正常完成,join所有线程
    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

说明

  • std::promise::set_exception会将异常传递给对应的std::future,主线程调用future.get()时会立即抛出该异常,无需等待其他线程。
  • 若需要主动终止其他未完成的线程,可以结合原子变量让子线程定期检查,一旦标记为终止就退出。

内容的提问来源于stack exchange,提问作者Mathieu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 08:03:35