2009-03-20 11 views
4

基本的に、あるスレッドが別のスレッドが処理する必要がある例外をスローする状況があります。私はブースト例外でこれをやろうとしていますが、行のどこかで型が失われてcatchブロックに捕らえられません。C++:boost :: exceptionのクロススレッド例外処理の問題

基本的にスレッドBは何かしたいと思っていますが、いろいろな理由でスレッドAで処理する必要があります(その理由を知りたいのであれば、なぜdirect3d 9デバイスを作成してリセットし、ウィンドウを作成した)。これらのアクションを実行している間に例外が発生すると、スレッドAはそれをキャッチしてスレッドBに渡し、スレッドBはそれを再発行して必要に応じて処理します。問題は、スレッドBにスローされた例外は、スレッドA. :(

私のプログラムのデバッグ出力、およびコードは以下の通りに投げられたものとは異なるように思われることである。

 
First-chance exception at 0x776b42eb ...: fllib::exception::Error at memory location 0x0019e590.. 
First-chance exception at 0x776b42eb ...: [rethrow] at memory location 0x00000000.. 
First-chance exception at 0x776b42eb ...: boost::exception_detail::clone_impl<boost::unknown_exception> at memory location 0x0019eed4.. 
//thread B 
... 
try 
{ 
    SendCallback(hwnd, boost::bind(&Graphics::create, this)); 
} 
catch(fllib::exception::Error &except)//example catch block, doesnt catch example exception 
{ 
    ...handle exception... 
} 

void SendCallback(HWND hwnd, boost::function<void()> call) 
{ 
    boost::exception_ptr *except_ptr = 
     (boost::exception_ptr*)SendMessage(hwnd, WM_CALLBACK, (unsigned)&call, SEND); 
    if(except_ptr)//if an exception occurred, throw it in thread B's context 
    { 
     boost::exception_ptr except = *except_ptr; 
     delete except_ptr; 
     boost::rethrow_exception(except); 
    } 
} 
//thread A 
LRESULT CALLBACK HookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    //check for our custom message 
    if(msg == WM_CALLBACK) 
    { 
     if(lParam == POST) 
     { 
      ... 
     } 
     else 
     { 
      boost::function<void()> *call = (boost::function<void()>*)wParam; 
      try 
      { 
       (*call)(); 
      } 
      catch(...) 
      { 
       return (unsigned)new boost::exception_ptr(boost::current_exception()); 
      } 
      return 0; 
     } 
    } 
    else 
    { 
     ... 
    } 
} 

void Graphics::create() 
{ 
...code that may throw exceptions... 
eg 
    throw fllib::exception::Error(L"Test Exception..."); 
} 
+0

@Neil ButterworthなぜVSデバッグ出力の一部を削除しましたか? –

+0

申し訳ありません - 私はちょうどタイトルを修正したと思った。 –

+0

あなたはどのように例外をスローしますか? – bayda

答えて

2

スレッドAからのすべてのスローはブースト:: enable_current_exceptionラッパーを使用していることを確認してください。thisを参照してください。

を「enable_current_exceptionは時間例外で と呼ばれていない限りオブジェクト は current_exceptionを使用して、それをコピーする 試みがUNKNOWN_EXCEPTIONの インスタンスを参照 exception_ptrを返すことがあり、スローイン式の中で使用されている。」

これを行うには、あなたがすべてキャッチする必要があるかもしれませんThread Aの例外をスローしてboost :: enable_current_exception(your_exception)でラップした後に再スローします。

また、_set_se_translatorを使用してラッパーを呼び出して例外オブジェクトにラップする場合を除いて、ゼロ除算のような構造化された例外に対しては、これは機能しません。

+0

「これを行うには...」可能性のある例外タイプごとにキャッチブロックなしでどのように行うことができますか? –

+0

www.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_ptr.htmlを参照してください。 – Emil

0

私はあなたがブーストの方法で例外をスローしなかったので、問題があると思います。

スレッドAのコンクリート例外をフックプロシージャで捕捉し、新しいオブジェクトにコピーしてポインタを返します。
結果がSendCallbackでチェックし、結果が存在する場合はNULLを返します。
例外がない場合は、必ずNULLが返されるようにしてください。

+0

私はすべての例外の種類ごとにcatchブロックが必要です。つまり、少なくともすべてのstd ::、boost ::およびすべてのコードで使用されていますか?そして、どのように私は何も期待できないvoid *例外を投げるのではなく、正しい型にそのポインタを戻すことができますか? –

+0

良い習慣すべての例外をstd :: exceptionのderiveteにする。 – bayda

+0

次は可能です some_error_info * result = 0; catch(const thirdparty :: exception&e) { 結果=新しいyour_own_error_type(e); { } キャッチ(ブースト* /から/ * excpetions)//同じ } キャッチ(のconstのstd ::例外&E)を行う {// 同じ } キャッチ(...) を{行います 結果=新しい不明なエラー(); } リターン結果; – bayda

1

私自身の例外タイプの解決策が見つかりました。

私はすべての例外タイプに2つの仮想メソッドを追加しました。

  • 仮想ベース* Clone();例外をクローンし、ヒープ上に新しい例外を返します。これは、キャッチブロックを離れるときにオリジナルのものが破壊されるという事実を回避します。
  • 仮想void ThrowAndDelete();これにより、ヒープのローカルコピーに例外オブジェクトが割り当てられ、ヒープ1が削除され(メモリリークを防ぐため)、スタックコピーがスローされます。これは、最も派生した型としてスローするという利点があります。

これは私が今簡単に行うことができることを意味:私はSTDについて何をすべきかわからない

void SendCallback(HWND hwnd, boost::function<void()> call) 
{ 
    fllib::exception::Base *except_ptr = 
     (fllib::exception::Base*)SendMessage(hwnd, WM_CALLBACK, (unsigned)&call, SEND); 
    if(except_ptr) except_ptr->ThrowAndDelete(); 
} 
LRESULT CALLBACK HookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    //check for our custom message 
    if(msg == WM_CALLBACK) 
    { 
     if(lParam == POST) 
     { 
      ... 
     } 
     else 
     { 
      boost::function<void()> *call = (boost::function<void()>*)wParam; 
      try 
      { 
       (*call)(); 
      } 
      catch(fllib::exception::Base &except) 
      { 
       return (unsigned)except.Clone(); 
      } 
      return 0; 
     } 
    } 
    else 
    { 
     ... 
    } 
} 

::とブースト::例外のvarityを彼らはにmtheodsを持っているように見えるいけないので、 likly手の前に扱われるべきではなく、例外の上記...しかし、95%+の効果私自身のクラスであり、そうでないものは、ほぼ確実とにかく未処理に行くつもりです...

1
  1. BOOST_THROW_EXCEPTIONを使用して例外をスローします。

  2. スレッド内でcatch(...)を実行し、boost :: current_exceptionを呼び出してboost :: exception_ptrに例外を埋め込みます。

  3. メインスレッドにexception_ptrをコピーしてから、rethrow_exceptionを呼び出します。これにより、catch(...)がスレッド内で捕捉した例外オブジェクトが再スローされます。

はwww.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_ptr.htmlを参照してください。