Sobes.tech
Middle+

How to check if an exception occurred in one of the threads?

sobes.tech AI

Answer from AI

There are several ways:

  1. Future and std::async: std::async returns a std::future. When trying to get the result from the future (for example, using future.get()) in the main thread, if an exception occurred in the asynchronous task, it will be re-thrown in the main thread.
  2. std::promise and std::future: A thread where an exception might occur can "capture" the exception and store it in a std::promise using promise.set_exception(). Another thread can obtain (promise.get_future()) the corresponding std::future and, upon calling future.get(), receive the stored exception.
  3. try-catch inside the thread and status passing: Wrap potentially "dangerous" code inside a try-catch block within the thread. In case of an exception, store a pointer to it (using std::current_exception()) or a special flag in a shared variable, with access synchronized.
  4. boost::exception library: boost::exception provides more powerful mechanisms for capturing, storing, and passing exceptions between threads, allowing attaching additional information to the exception.

Example with std::async:

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

// Function that may throw an exception
int divide(int a, int b) {
    if (b == 0) {
        throw std::runtime_error("Division by zero!");
    }
    return a / b;
}

int main() {
    // Launch an asynchronous task
    std::future<int> fut = std::async(std::launch::async, divide, 10, 0);

    try {
        // Attempt to get the result. If an exception occurred, it will be thrown here.
        int result = fut.get();
        std::cout << "Result: " << result << std::endl;
    } catch (const std::exception& e) {
        // Handle the exception that occurred in the other thread
        std::cerr << "Caught exception from thread: " << e.what() << std::endl;
    }

    return 0;
}

Example with std::promise and std::future:

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

void worker_function(std::promise<int>&& prom) {
    try {
        // Code that may throw an exception
        int result = 5 / 0; // Suppose an error occurs here
        prom.set_value(result); // Set successful value
    } catch (...) {
        // Capture the current exception
        try {
            prom.set_exception(std::current_exception()); // Set the exception
        } catch (...) {
            // An error occurred while setting the exception (unlikely)
        }
    }
}

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

    // Launch a thread with worker_function
    std::thread t(worker_function, std::move(prom));

    try {
        // Try to get the result from future
        int result = fut.get();
        std::cout << "Result: " << result << std::endl;
    } catch (const std::exception& e) {
        // Handle the exception that was set in the promise
        std::cerr << "Caught exception from thread: " << e.what() << std::endl;
    }

    t.join(); // Wait for the thread to finish

    return 0;
}

The choice of method depends on the application's architecture and error handling requirements. std::async and std::future are the simplest way to pass results and exceptions from one-off tasks. std::promise and std::future offer more flexibility. Manual status or exception storage is suitable for specific scenarios with custom synchronization logic.

How to check if an exception occurred in one of the… - sobes.tech