14

一部のマルチスレッドコードでは、すべての例外をキャプチャして、それらを単一の例外処理スレッドに渡したいと思います。メッセージパッシングフレームワークは次のとおりです。

#include <exception>

struct message
{
    virtual ~message() = default;
    virtual void act() = 0;
};

struct exception_message : message
{
    std::exception_ptr ep;

    virtual void act()
    {
        std::rethrow_exception(ep);
    }

    // ...
};

ユースケースは次のとおりです。

try
{
    // ...
}
catch (...)
{
    exception_message em { std::current_exception(); }
    handler_thread.post_message(em);
}

ハンドラースレッドはすべてのメッセージと呼び出しact()を調べ、独自のtry / catchブロックをインストールして、投稿されたすべての例外を処理できます。

このメッセージのコピーを複数の受信者に送信するとどうなるのでしょうか。一般に、メッセージには任意の数の受信者がいる可能性があるため、例外伝播メッセージに恣意的な制限を課したくありません。これexception_ptrは、「共有所有権」スマートポインターとして文書化されており、「rethrow_exceptionデータ競合を導入しません」。

だから私の質問:アクティブな例外をに保存しexception_ptr、ポインタをコピーし、rethrow_exception複数回呼び出すことによって、アクティブな例外を複製することは正当ですか?

4

1 に答える 1

6

私の基準の理解から、それは合法です。ただし、再スローでは例外が複製されないため、共有例外オブジェクト自体を変更して他のスレッドからアクセスすると、共有例外オブジェクト自体がデータ競合状態になります。例外が読み取り専用(一度スローされる)の場合、問題は発生しないはずです。

保存期間について:

15.1例外のスロー[except.throw]

4 3.7.4.1に記載されている場合を除き、例外オブジェクトのメモリは不特定の方法で割り当てられます。ハンドラーが再スローによって終了した場合、同じ例外に対して制御が別のハンドラーに渡されます。例外オブジェクトは、例外の最後に残っているアクティブハンドラーが再スロー以外の方法で終了した後、またはstd::exception_ptr例外オブジェクトを参照するタイプ(18.8.5)の最後のオブジェクトが破棄された後のいずれか遅い方の後に破棄されます。前者の場合、ハンドラーの例外宣言で宣言されたオブジェクト(存在する場合)が破棄された直後に、ハンドラーが終了したときに破棄が発生します。後者の場合、破壊はリターンのデストラクタの前に発生しstd::exception_ptrます。

データ競合について:

18.8.5例外の伝播[伝播]

7データ競合の存在を判断するために、オブジェクトに対する操作は、オブジェクト自体にexception_ptrのみアクセスして変更するものとし、オブジェクトが参照する例外は変更しないものとします。同じ例外オブジェクトを参照するonオブジェクトをexception_ptr使用しても、データ競合が発生することはありません。[注:(コピーではなく)同じ例外オブジェクトを再スローする場合、その再スローされた例外オブジェクトへの同時アクセスにより、データ競合が発生する可能性があります。特定の例外を参照するオブジェクトの数を変更しても、データの競合は発生しません。—エンドノート]rethrow_exceptionexception_ptrrethrow_exceptionexception_ptr

についてrethrow

[[noreturn]] void rethrow_exception(exception_ptr p);

9必須pヌルポインタであってはなりません。

10スロー:pが参照する例外オブジェクト。

于 2012-10-02T13:16:13.883 に答える