スレッド間で例外を持つこと

1 種類のスレッドから別の状態に 例外を伝える Visual C++ のサポート。例外を持つことは1 種類のスレッドで例外をキャッチし例外を別のスレッドでこのように見えることができます。たとえばプライマリ スレッドはセカンダリ スレッドによってスローされたすべての例外を処理するマルチスレッド アプリケーションの作成にこの機能を使用できます。例外を持つことは並列プログラミングのライブラリまたはシステムを作成する開発者は主に便利です。例外を持つことを実行するにはVisual C++ で exception_ptr の型と current_exceptionrethrow_exception と copy_exception 関数を提供します。

namespace std 
{
   typedef unspecified exception_ptr; 
   exception_ptr current_exception();
   void rethrow_exception(exception_ptr p);
   template<class E> 
       exception_ptr copy_exception(E e);
}

パラメーター

パラメーター

Description

unspecified

exception_ptr の型を実装するために使用される未指定の内部クラス。

p

exception_ptr のオブジェクトを参照する例外。

E

例外を表すクラスです。

e

パラメーターの E クラスのインスタンス。

戻り値

current_exception 関数の戻り値 exception_ptr のオブジェクトを参照する現在処理されている例外。例外が処理中でない場合関数の戻り値例外に関連付けられていない exception_ptr のオブジェクト。

例外が e のパラメーターで指定した参照して copy_exception 関数の戻り値 exception_ptr のオブジェクト。

解説

シナリオ

変数の作業量を処理するようにスケーリングできるアプリケーションを作成するとします。この目的を達成するためにジョブが必要になると頭文字プライマリ スレッドが同じ数のセカンダリ スレッドを作成するマルチスレッド アプリケーションをデザインします。セカンダリ スレッドがリソースを管理し作業負荷のバランスをとりスループットが向上するプライマリ スレッドができます。作業の配布によってマルチスレッド アプリケーションではシングルスレッド アプリケーションのパフォーマンスが向上します。

ただしセカンダリ スレッドが例外をスローした場合プライマリ スレッドにはを処理する必要があります。これには一貫している必要なため統一された方法で例外を処理するアプリケーションはセカンダリ スレッドの数に関係なく。

解決方法

上のシナリオを処理するためにスレッド間で例外を持つ C++ 規格サポート。セカンダリ スレッドが例外をスローした場合その例外は 現在の例外に なります。実際のようにして現在の例外が 実行時に なります。現在の例外を catch ハンドラーが返す例外がスローされた時点から実行中になります。

セカンダリ スレッドが catch ブロックで現在の例外をキャッチしexception_ptr のオブジェクトで例外を保存するに current_exception の関数を呼び出します。exception_ptr のオブジェクトはセカンダリ スレッドとプライマリ スレッドで使用できる必要があります。たとえばexception_ptr のオブジェクトはアクセスがミューテックスによって制御されるグローバル変数です。1 種類のスレッドで例外は別のスレッドによってアクセスできる形式に変換できることを示す 例外が 意味する用語の コピー 。

次にプライマリ スレッドは抽出が exception_ptr のオブジェクトから例外をスロー rethrow_exception の関数を呼び出すします。例外がスローされた場合プライマリ スレッドで現在の例外になります。つまり例外プライマリ スレッドで作成された表示されます。

最後にプライマリ スレッドは catch ブロックとプロセスの現在の例外をキャッチするか高レベルの例外ハンドラーにスローできます。またはプライマリ スレッドは例外を無視しプロセスが終了してからできます。

ほとんどのアプリケーションはスレッド間で例外を伝達する必要はありません。ただしこの機能によってシステムがセカンダリ スレッドプロセッサまたはコア間のスレッドを使用できるため並列計算システムに便利です。並列コンピューティング環境では単一の専用スレッドはセカンダリ スレッドからすべての例外を処理しアプリケーションに一貫した例外処理モデルを指定できます。

C++ 標準委員会の提案については「スレッド間で例外」に伝えるための言語サポートいうパブリック N2179 文書番号をインターネットを検索します。

例外処理モデルとコンパイラ オプション

アプリケーションの例外処理モデルは例外をキャッチして実現できるかどうかを判定します。Visual C++ ではC++ 例外は構造化例外処理の例外と共通言語ランタイム例外を (SEH) 処理できる 3 種類のモデルをサポート (CLR) します。アプリケーションの例外処理モデルを指定する /EH/clr コンパイラ オプションを使用します。

コンパイラ オプションとプログラミング ステートメントの次の組み合わせにのみ例外を持つことができます。他の組み合わせは例外をキャッチできませんがキャッチできません。例外を持つことができません。

  • /EHa のコンパイラ オプションおよび catch のステートメントはと C++ 例外を持つことができます。

  • /EHa/EHs/EHsc のコンパイラ オプションおよび catch のステートメントはC++ 例外を持つことができます。

  • /CLR または /CLR:pure のコンパイラ オプションおよび catch のステートメントはC++ 例外を持つことができます。/CLR コンパイラ オプションは /EHa オプションの指定を意味します。コンパイラがマネージ例外を持つことがサポートされないことに注意してください。これは SystemException のクラスから派生するマネージ例外が既にスレッド間で共通の languange のランタイム機能を使用して移動するオブジェクトであるためです。

    セキュリティに関するメモセキュリティに関するメモ

    また/EHsc コンパイラ オプションを指定することをお勧めしてC++ 例外だけをキャッチします。省略記号の 例外宣言 catch(...)() を除く /EHa または /CLR のコンパイラ オプションと catch のステートメントを使用するとセキュリティ上の脅威についてもあります。おそらく一部の特定の例外をキャプチャするために catch のステートメントを使用しようとします。ただしcatch(...) のステートメントではすべての C++ と SEH を致命的にする必要がある予期しないものも含めて例外をキャプチャします。予期しない例外を無視または誤って処理すると悪意のあるコードではプログラムのセキュリティ規則をその機会を使用できます。

使用方法

以降のセクションでは exception_ptr の型および current_exception 使用して例外を rethrow_exception する方法および copy_exception 関数について説明します。

Dd293602.collapse_all(ja-jp,VS.110).gifexception_ptr の型

ユーザーが指定した例外または例外の現在のインスタンスを参照するために exception_ptr のオブジェクトを使用します。Microsoft の実装では例外は EXCEPTION_RECORD の構造体によって表されます。exception_ptr の各オブジェクトは例外を表す EXCEPTION_RECORD のコピーへのポインターを構成する例外参照フィールドがあります。

exception_ptr の変数を宣言すると変数は例外に関連付けられません。つまり例外のフィールド参照は null です。exception_ptr のこのようなオブジェクトはnull の exception_ptr と 呼ばれます。

exception_ptr のオブジェクトに例外を割り当てるには current_exception または copy_exception の関数を使用します。exception_ptr の例外を変数に代入すると例外のコピーへの変数の例外の参照フィールドのポインター。例外をコピーするメモリが不足している場合 std:: bad_alloc の例外のコピーへの参照の例外フィールドのポインター。current_exception または copy_exception の関数が例外を他の理由でコピーできない場合関数呼び出し現在のプロセスを終了する terminate (CRT) の関数。

名前にもかかわらずexception_ptr のオブジェクト自体はポインターではありません。はポインターのセマンティクスに従いますがポインターのメンバー アクセス () または間接 ->(*) 演算子では使用できません。exception_ptr のオブジェクトにパブリック データ メンバーまたはメンバー関数がありません。

比較 :

exception_ptr の 2 個のオブジェクトを比較するために == 等号 () と等しくない !=() 演算子を使用できます。演算子は例外を表す EXCEPTION_RECORD 構造のバイナリ値 (ビット パターン) は比較されません。代わりに演算子は exception_ptr のオブジェクトの例外の参照フィールドのアドレスを比較します。その結果空白の exception_ptr および NULL 値は等しくなります。

Dd293602.collapse_all(ja-jp,VS.110).gifcurrent_exception の関数

catch ブロックの current_exception の関数を呼び出します。例外が実行中の場合と catch ブロックが例外をキャッチすることができます current_exception 関数の戻り値 exception_ptr のオブジェクトを参照する例外。そうしないと関数の戻り値 exception_ptr の空のオブジェクト。

詳細:

current_exception の関数は catch のステートメントは 例外宣言 のステートメントを指定しているかどうかを実行時に例外をキャプチャします。

現在の例外のデストラクターが catch ブロックの終わりでキャッチする例外呼び出されます。ただしデストラクターの current_exception の関数を呼び出すことは 関数の戻り値 exception_ptr のオブジェクトを参照する現在の例外。

現在の例外のさまざまなコピーを示す current_exception 関数の戻り値の exception_ptr のオブジェクトに連続して呼び出す。その結果オブジェクトはコピーに同じバイナリ値がある場合でも複数のコピーを示すため等しくないと比較します。

SEH 例外 :

/EHa のコンパイラ オプションを使用するとC.C++ の catchブロックで例外をキャッチできます。current_exception 関数の戻り値 exception_ptr のオブジェクトを参照する SEH 例外。と rethrow_exception の関数は引数として exception_ptr の によって伝達されるオブジェクトで呼び出すと例外がスローされます。

でと __finally の終了ハンドラー__except の例外ハンドラーまたは __except フィルター式を呼び出すと current_exception 関数の戻り値を null に exception_ptr。

変換例外は入れ子になった例外をサポートしていません。入れ子になった例外も処理中に別の例外がスローされた場合に発生します。入れ子になった例外をキャッチした場合関連の例外を説明する EXCEPTION_RECORD 構造のチェーンに EXCEPTION_RECORD.ExceptionRecord データ メンバーのポインター。current_exception の関数は ExceptionRecord データ メンバーがゼロになる exception_ptr のオブジェクトを返すので入れ子になった例外をサポートしていません。

SEH 例外をキャッチした場合EXCEPTION_RECORD.ExceptionInformation データ メンバーの配列のポインターから参照されるメモリ管理する必要があります。メモリが exception_ptr の対応するオブジェクトの有効期間中に有効でありexception_ptr オブジェクトが削除されたときにメモリが解放されることを保証する必要があります。

コピーの例外の (SE) 機能とともに構造化例外の変換関数を使用できます。元のではなく変換された例外を SEH 例外参照する C++. C++ 例外に変換される場合例外 current_exception 関数の戻り値 exception_ptr。rethrow_exception の関数に変換された例外ではなく元の例外をスローします。SE の変換関数の詳細については_set_se_translator を参照してください。

Dd293602.collapse_all(ja-jp,VS.110).gifrethrow_exception の関数

exception_ptr のオブジェクトでキャッチした例外を保存するとプライマリ スレッドはオブジェクトを操作できます。プライマリ スレッドでは引数として exception_ptr のオブジェクトとともに rethrow_exception の関数を呼び出します。rethrow_exception の関数は exception_ptr のオブジェクトから例外を抽出しプライマリ スレッドのコンテキストで例外をスローします。rethrow_exception の関数の p のパラメーターが null の exception_ptr 場合関数はをスローします。std:: bad_exception

これで抽出例外はプライマリ スレッドで現在の例外であり他の例外と同様に扱うことができます。例外をキャッチした場合はすぐに処理したり高レベルの例外ハンドラーに送信するために throw のステートメントを使用します。それ以外の場合は何も実行せず既定のシステムの例外ハンドラーがプロセスを終了できるようにします。

Dd293602.collapse_all(ja-jp,VS.110).gifcopy_exception の関数

copy_exception の関数はインスタンスを参照する引数としてクラスのインスタンスを受け取りexception_ptr を返します。通常クラス オブジェクトに対して引数ですが引数として copy_exception の関数への 例外クラス のオブジェクトを指定します。

copy_exception の関数を呼び出してC++ 例外を . でcatch ブロックからスローするのと同じ次に呼び出すことが current_exception の関数を exception_ptr のオブジェクトを返すに参照する例外をキャッチします。copy_exception の関数の Microsoft の実装では例外をスローしをキャッチしよりも効率的です。

アプリケーションでは通常copy_exception の関数を必要とせず使用は推奨されていません。

使用例

次の例では1 種類のスレッドから別の型への標準 C++ 例外とカスタム C++ 例外処理を行います。

// transport_exception.cpp
// compile with: /EHsc /MD
#include <windows.h>
#include <stdio.h> 
#include <exception>
#include <stdexcept>

using namespace std;

// Define thread-specific information.
#define THREADCOUNT 2
exception_ptr aException[THREADCOUNT]; 
int           aArg[THREADCOUNT];

DWORD WINAPI ThrowExceptions( LPVOID ); 

// Specify a user-defined, custom exception. 
// As a best practice, derive your exception 
// directly or indirectly from std::exception. 
class myException : public std::exception { 
};
int main()
{
    HANDLE aThread[THREADCOUNT];
    DWORD ThreadID;

    // Create secondary threads.
    for( int i=0; i < THREADCOUNT; i++ )
    {
        aArg[i] = i;
        aThread[i] = CreateThread( 
            NULL,       // Default security attributes.
            0,          // Default stack size.
            (LPTHREAD_START_ROUTINE) ThrowExceptions, 
            (LPVOID) &aArg[i], // Thread function argument.
            0,          // Default creation flags.
            &ThreadID); // Receives thread identifier.
        if( aThread[i] == NULL )
        {
            printf("CreateThread error: %d\n", GetLastError());
            return -1;
        }
    } 

    // Wait for all threads to terminate.
    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE); 
    // Close thread handles.
    for( int i=0; i < THREADCOUNT; i++ ) {
        CloseHandle(aThread[i]); 
    }

    // Rethrow and catch the transported exceptions.
    for ( int i = 0; i < THREADCOUNT; i++ ) {
        try {
            if (aException[i] == NULL) {
                printf("exception_ptr %d: No exception was transported.\n", i);
            }
            else {
                rethrow_exception( aException[i] );
            }  
        }
        catch( const invalid_argument & ) {
            printf("exception_ptr %d: Caught an invalid_argument exception.\n", i);
        }
        catch( const myException & ) {
            printf("exception_ptr %d: Caught a  myException exception.\n", i);
        }
    }
} 
// Each thread throws an exception depending on its thread 
// function argument, and then ends. 
DWORD WINAPI ThrowExceptions( LPVOID lpParam ) 
{ 
    int x = *((int*)lpParam);
    if (x == 0) {
        try {
            // Standard C++ exception.
            // This example explicitly throws invalid_argument exception. 
            // In practice, your application performs an operation that 
            // implicitly throws an exception.
            throw invalid_argument("A C++ exception.");
        }  
        catch ( const invalid_argument & ) { 
            aException[x] = current_exception();
        } 
    }
    else {
        // User-defined exception.
        aException[x] = copy_exception( myException() ); 
    }
    return TRUE; 
}
  
  

必要条件

ヘッダー : <exception>

参照

関連項目

Visual C++ の例外処理

EXCEPTION_RECORD の構造

ハンドラー構文

/EH (例外処理モデル)

/clr (共通言語ランタイムのコンパイル)