How can I propagate exceptions between threads? How can I propagate exceptions between threads? multithreading multithreading

How can I propagate exceptions between threads?


C++11 introduced the exception_ptr type that allows to transport exceptions between threads:

#include<iostream>#include<thread>#include<exception>#include<stdexcept>static std::exception_ptr teptr = nullptr;void f(){    try    {        std::this_thread::sleep_for(std::chrono::seconds(1));        throw std::runtime_error("To be passed between threads");    }    catch(...)    {        teptr = std::current_exception();    }}int main(int argc, char **argv){    std::thread mythread(f);    mythread.join();    if (teptr) {        try{            std::rethrow_exception(teptr);        }        catch(const std::exception &ex)        {            std::cerr << "Thread exited with exception: " << ex.what() << "\n";        }    }    return 0;}

Because in your case you have multiple worker threads, you will need to keep one exception_ptr for each of them.

Note that exception_ptr is a shared ptr-like pointer, so you will need to keep at least one exception_ptr pointing to each exception or they will be released.

Microsoft specific: if you use SEH Exceptions (/EHa), the example code will also transport SEH exceptions like access violations, which may not be what you want.


Currently, the only portable way is to write catch clauses for all the types of exceptions that you might like to transfer between threads, store the information somewhere from that catch clause and then use it later to rethrow an exception. This is the approach taken by Boost.Exception.

In C++0x, you will be able to catch an exception with catch(...) and then store it in an instance of std::exception_ptr using std::current_exception(). You can then rethrow it later from the same or a different thread with std::rethrow_exception().

If you are using Microsoft Visual Studio 2005 or later, then the just::thread C++0x thread library supports std::exception_ptr. (Disclaimer: this is my product).


If you're using C++11, then std::future might do exactly what you're looking for: it can automagically trap exceptions that make it to the top of the worker thread, and pass them through to the parent thread at the point that std::future::get is called. (Behind the scenes, this happens exactly as in @AnthonyWilliams' answer; it's just been implemented for you already.)

The down side is that there's no standard way to "stop caring about" a std::future; even its destructor will simply block until the task is done. [EDIT, 2017: The blocking-destructor behavior is a misfeature only of the pseudo-futures returned from std::async, which you should never use anyway. Normal futures don't block in their destructor. But you still can't "cancel" tasks if you're using std::future: the promise-fulfilling task(s) will continue running behind the scenes even if nobody is listening for the answer anymore.] Here's a toy example that might clarify what I mean:

#include <atomic>#include <chrono>#include <exception>#include <future>#include <thread>#include <vector>#include <stdio.h>bool is_prime(int n){    if (n == 1010) {        puts("is_prime(1010) throws an exception");        throw std::logic_error("1010");    }    /* We actually want this loop to run slowly, for demonstration purposes. */    std::this_thread::sleep_for(std::chrono::milliseconds(100));    for (int i=2; i < n; ++i) { if (n % i == 0) return false; }    return (n >= 2);}int worker(){    static std::atomic<int> hundreds(0);    const int start = 100 * hundreds++;    const int end = start + 100;    int sum = 0;    for (int i=start; i < end; ++i) {        if (is_prime(i)) { printf("%d is prime\n", i); sum += i; }    }    return sum;}int spawn_workers(int N){    std::vector<std::future<int>> waitables;    for (int i=0; i < N; ++i) {        std::future<int> f = std::async(std::launch::async, worker);        waitables.emplace_back(std::move(f));    }    int sum = 0;    for (std::future<int> &f : waitables) {        sum += f.get();  /* may throw an exception */    }    return sum;    /* But watch out! When f.get() throws an exception, we still need     * to unwind the stack, which means destructing "waitables" and each     * of its elements. The destructor of each std::future will block     * as if calling this->wait(). So in fact this may not do what you     * really want. */}int main(){    try {        int sum = spawn_workers(100);        printf("sum is %d\n", sum);    } catch (std::exception &e) {        /* This line will be printed after all the prime-number output. */        printf("Caught %s\n", e.what());    }}

I just tried to write a work-alike example using std::thread and std::exception_ptr, but something's going wrong with std::exception_ptr (using libc++) so I haven't gotten it to actually work yet. :(

[EDIT, 2017:

int main() {    std::exception_ptr e;    std::thread t1([&e](){        try {            ::operator new(-1);        } catch (...) {            e = std::current_exception();        }    });    t1.join();    try {        std::rethrow_exception(e);    } catch (const std::bad_alloc&) {        puts("Success!");    }}

I have no idea what I was doing wrong in 2013, but I'm sure it was my fault.]