1. ホーム
  2. c++

[解決済み] スレッド間で例外を伝播させるにはどうしたらいいですか?

2022-05-14 05:15:52

質問

1つのスレッドが呼び出す関数があります(これをメインスレッドと名付けます)。関数の本体内で、CPU に集約された作業を行うために複数のワーカスレッドを生成し、すべてのスレッドが終了するのを待ち、その後メインスレッドで結果を返します。

その結果、呼び出し元は関数を素直に使うことができ、内部では複数のコアを使用することになります。

今のところすべて良好です。

問題は、例外の処理です。 ワーカスレッドで例外が発生してアプリケーションがクラッシュするのは困ります。 関数の呼び出し元が、メイン スレッドで例外をキャッチできるようにしたいのです。 ワーカスレッドで例外をキャッチし、それをメインスレッドに伝搬して、そこから巻き戻しを続けさせなければなりません。

どのようにしてこれを行うのでしょうか。

一番思いつくのは

  1. ワーカスレッドで様々な例外をキャッチする(std::exceptionといくつかの独自のもの)。
  2. 例外の型とメッセージを記録します。
  3. ワーカスレッドで記録されたどのようなタイプの例外でも再スローする、メインスレッド上の対応するスイッチステートメントを用意する。

これは、限られた例外タイプしかサポートしないという明らかな欠点があり、新しい例外タイプが追加されるたびに修正が必要になります。

どのように解決するのか?

C++11 では exception_ptr 型が導入され、スレッド間で例外を転送することができるようになりました。

#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;
}

あなたの場合、複数のワーカスレッドを持っているので、1つの exception_ptr をそれぞれ保持する必要があります。

なお exception_ptr は共有 ptr ライクなポインタなので、少なくとも1つの exception_ptr を各例外を指しておく必要があります。

Microsoft 固有のもの: SEH 例外を使用する場合 ( /EHa ) を使用する場合、サンプルコードはアクセス違反のような SEH 例外も送りますが、それはあなたが望むものではない可能性があります。