如果您使用的是 C++11,那么 std::future 可能完全符合您的要求:它可以自动捕获使其到达工作线程顶部的异常,并将它们传递给父级在调用std::future::get 时线程。 (在幕后,这与@AnthonyWilliams 的回答完全相同;它已经为您实施了。)
缺点是没有标准的方法来“停止关心”std::future;甚至它的析构函数也会简单地阻塞,直到任务完成。 [编辑,2017:阻塞析构函数行为是从std::async 返回的伪期货的错误特征仅,无论如何你都不应该使用它。正常的期货不会阻塞它们的析构函数。但是,如果您使用 std::future,您仍然不能“取消”任务:即使没有人再听答案,承诺履行任务仍将继续在幕后运行。] 这是一个可能会阐明我的意思的玩具示例:
#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());
}
}
我只是尝试使用std::thread 和std::exception_ptr 编写一个类似工作的示例,但是std::exception_ptr 出了点问题(使用libc++)所以我还没有让它真正工作。 :(
[编辑,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!");
}
}
我不知道我在 2013 年做错了什么,但我确信这是我的错。]