If you use C ++ 11, then std::future can do exactly what you are looking for: it can automatically catch exceptions that fall at the top of the workflow and pass them to the parent element, the thread at the point at which std::future::get is called std::future::get . (Behind the scenes, this happens exactly the same as in @AnthonyWilliams answer, it has just been implemented for you already.)
On the other hand, there is no standard way to “stop caring” about std::future ; even its destructor will simply block until the task is completed. [EDIT, 2017: The behavior of a blocking destructor is an error only for pseudo-releases returned from std::async , which you should never use in any case. Normal futures are not blocked in their destructor. But you still can't “cancel” tasks if you use std::future : fulfilled tasks promises will be kept behind the scenes, even if no one else is responsible for the answer.] Here's a toy example that can 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 an example that looked like work using std::thread and std::exception_ptr , but something was wrong with std::exception_ptr (using libC ++), so I haven't actually got it 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 don’t know what I did wrong in 2013, but I’m sure it was my mistake.]
Quuxplusone Jan 25 '13 at 1:18 2013-01-25 01:18
source share