結論
こんな感じに書けば良さそうです(C++11以降)。
#include <iostream>
#include <thread>
#include <exception>
#include <functional>
#include <mutex>
/* std::threadに渡す関数の例 */
std::mutex cout_mtx;
template <typename T>
void add(const T& a, const T& b) {
std::lock_guard<std::mutex> lock(cout_mtx);
std::cout << a + b << std::endl;
}
void merge_str(const std::string& a, const std::string& b) {
if(a == "maao" || b == "maao") {
throw std::invalid_argument("\"maao\" is an invalid word");
}
std::lock_guard<std::mutex> lock(cout_mtx);
std::cout << a + b << std::endl;
}
/* 例外を親スレッドに集約する記述の例 */
void run() {
std::exception_ptr e_ptr;
// std::threadに渡す関数をwrapするlambda式
// 子スレッドの処理中にcatchされた例外を、
// 親スレッドのオブジェクトである例外ポインタ(e_ptr)にセットする
auto gen_th_func = [&](auto f) -> auto {
return [&]() -> void {
try { f(); } catch(...) { e_ptr = std::current_exception(); }
};
};
// スレッドを起動し、終了を待つ
auto th1 = std::thread(gen_th_func([&]() { add(1, 1); }));
auto th2 = std::thread(gen_th_func([&]() { add(0.1, 0.1); }));
auto th3 = std::thread(gen_th_func([&]() { merge_str("hoge", "huga"); }));
auto th4 = std::thread(gen_th_func([&]() { merge_str("piyo", "maao"); }));
th1.join();
th2.join();
th3.join();
th4.join();
// 例外ポインタが子スレッド内でthrowされた例外を指していれば、その例外を再送する
if(e_ptr != nullptr) {
std::rethrow_exception(e_ptr);
}
}
int main() {
try {
run();
}
catch(const std::exception& e) {
std::cout << e.what() << std::endl;
}
}
実行結果
$ g++ -o test test.cpp -pthread $ ./test 2 0.2 hogehuga "maao" is an invalid word
ただし、「ある子スレッドが投げた例外を他の子スレッドが検知する」といったことは出来ません。そのような処理が必要な場合は、フラグをスレッド間の共有リソースとして用意して、上記のlambda式中のcatch文の中で書き換えるなどの処置が必要です。