2012-04-11 11 views
0

ActiveXビデオプレーヤーを開発中です。 DLLのインプロセスコンポーネントです。私はVisual Studio 2010を使用しています。win32スレッドが予期せずactiveXで終了する(C++)

コンポーネントがロードされたらDirect3D9オブジェクトとDirect3D9デバイスを作成し、コンポーネントのアンロードを停止してこれらのオブジェクトを破棄する別のスレッドが必要です。コンポーネントが実行されている間、私はこのスレッドが定期的にTestCooperativeLevelを呼び出し、必要に応じてD3Dデバイスをリセットしたいと思います。

クライアントアプリケーションが自分のプレーヤーのインスタンスを複数作成できるため、この作業を行っていますが、D3D9オブジェクトとデバイスのインスタンスを1つだけ使用することを強くお勧めします。

staticメソッドとメンバを持つクラスを宣言しました。そのコンストラクタが_beginthreadex()を呼び出し、スレッドを開始します。

コード抜粋(WITH ERRORS)は次のとおりです。

// .h 
class D3DManager { 
    static mutex d3; // mutex is my own class, just a wrapper around CriticalSection 
    static LPDIRECT3D9 g_d3d; 
    static LPDIRECT3DDEVICE9 g_d3ddev; 
    static D3DPRESENT_PARAMETERS g_d3dpp; 
    static int g_d3d_counter; 
    static HANDLE hthread; 
    static HANDLE exitev; 
    static bool exit_flag; 
    static mutex exit_mutex; 

public: 
    D3DManager(); 
    ~D3DManager(); 

    static unsigned int __stdcall thread(void *); 
    static void stop(void) { 
         exit_mutex.lock(); 
         exit_flag = true; 
         SetEvent(exitev); 
         exit_mutex.unlock(); } 

    static bool exit_signal(void) { 
         exit_mutex.lock(); 
         bool result = exit_flag; 
         exit_mutex.unlock(); 
         return exit_flag; } 

    static void CreateD3DDevice(LPDIRECT3D9& d3dobj, LPDIRECT3DDEVICE9& d3ddev); 
    static void DestroyD3DDevice(void); 
    static void GetSwapChain(HWND hwnd, LPDIRECT3DSWAPCHAIN9& chain); 
    static void release_d3d(void); 
    static void LockDevice(void) { d3.lock(); }; 
    static void UnlockDevice(void) { d3.unlock(); }; 
}; 



//.cpp 

        mutex D3DManager::d3; 
       LPDIRECT3D9 D3DManager::g_d3d = NULL; 
     LPDIRECT3DDEVICE9 D3DManager::g_d3ddev = NULL; 
    D3DPRESENT_PARAMETERS D3DManager::g_d3dpp; 
         int D3DManager::g_d3d_counter = 0; 
        HANDLE D3DManager::hthread; 
        HANDLE D3DManager::exitev; 
        bool D3DManager::exit_flag = false; 
        mutex D3DManager::exit_mutex; 

      // this variable will be single and shared by all activeX instances 
      static D3DManager d3dm; 


    D3DManager::D3DManager() 
    { 
     exitev = CreateEvent(NULL, true, false, NULL); 
     hthread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL); 
     _OutputDebugString("D3DManager: thread created handle %x\n", hthread); // my wrapper around OutputDebugString 

    } 

    D3DManager::~D3DManager() 
    { 
     stop(); 
     HRESULT hr = WaitForSingleObject(hthread, 1000); 
     if (hr == WAIT_ABANDONED) { 
      TerminateThread(hthread, 0); 
      release_d3d(); 
     } 
     CloseHandle(exitev); 
    } 

    unsigned int __stdcall D3DManager::thread(void *) 
    { 
     create_d3d9(); 
     while(!exit_signal()) { 
      WaitForSignleObject(exitev, 500); 
      d3.lock(); 
      HRESULT hr = g_d3ddev->TestCooperativeLevel(); 
      switch(hr) { 
       case S_OK: 
         break; 
       case D3DERR_DEVICENOTRESET : 
         // Fill DISPLAYPARAMETERS 
         g_d3ddev->Reset(); 
         break; 
       default: 
         break; 
      } 
      d3.unlock(); 
     } 

    ///////// This text is never seen 

     OutputDebugString("D3dManagert exit from while loop\n"); 

    //////// 
     release_d3d(); 
     _endthreadex(0); 
     return 0; 
    } 

私のコンポーネントは、C#で書かれたWindowsフォームフォームに組み込まれています。

問題は、フォームを閉じるときにスレッドがループ中に終了し、その後にコードに到達しないことです。私はOutputDebugStringからテキストを見たことがなく、release_d3d()も決して呼び出されず、メモリリークについてのd3dデバッグから多くのメッセージが表示されます。ブレークポイントを設定すると、決してヒットしません。

私が見るすべてのメッセージです:私は、デストラクタにブレークポイントを設定すると

The thread 'Win32 Thread' (0x1044) has exited with code 0 (0x0) 

、私はそれが打撃を受けるが、ビデオメモリリークについてのメッセージの後に。

スタジオでC++例外とWin32例外でデバッグブレークを有効にしましたが、トリガされていません。

更新。

D3DManager::D3DManager() 
    { 
     exitev = CreateEvent(NULL, true, false, NULL); 
     hthread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL); 
     _OutputDebugString("D3DManager: thread created handle %x\n", hthread); 
     atexit(&release_d3d); 
    } 

まだ運: は、すべてのスレッドが_exit、それらのいずれかがexitを呼び出したときに、終了、またはabortまたはExitProcessatexitハンドラコンストラクタでstting試されていることをMSDNで読みました。私はビデオメモリリークに関するメッセージを受け取った後にrelease_d3dが呼び出されます。さらに私は例外的な誤りを持っています。

更新2.

ここで編集したコード

// .h 
class D3DManager { 
    static mutex d3; // mutex is my own class, just a wrapper around CriticalSection 
    static LPDIRECT3D9 g_d3d; 
    static LPDIRECT3DDEVICE9 g_d3ddev; 
    static D3DPRESENT_PARAMETERS g_d3dpp; 
    static int g_d3d_counter; 
    static HANDLE hthread; 
    static HANDLE exitev; 

public: 
    D3DManager(); 
    ~D3DManager(); 

    static unsigned int __stdcall thread(void *); 
    static void stop(void) { SetEvent(exitev); } 

    static void CreateD3DDevice(LPDIRECT3D9& d3dobj, LPDIRECT3DDEVICE9& d3ddev); 
    static void DestroyD3DDevice(void); 
    static void GetSwapChain(HWND hwnd, LPDIRECT3DSWAPCHAIN9& chain); 
    static void release_d3d(void); 
    static void LockDevice(void) { d3.lock(); }; 
    static void UnlockDevice(void) { d3.unlock(); }; 
}; 



//.cpp 

        mutex D3DManager::d3; 
       LPDIRECT3D9 D3DManager::g_d3d = NULL; 
     LPDIRECT3DDEVICE9 D3DManager::g_d3ddev = NULL; 
    D3DPRESENT_PARAMETERS D3DManager::g_d3dpp; 
         int D3DManager::g_d3d_counter = 0; 
        HANDLE D3DManager::hthread; 
        HANDLE D3DManager::exitev; 

      // this variable will be single and shared by all activeX instances 
      static D3DManager d3dm; 


    D3DManager::D3DManager() 
    { 
     exitev = CreateEvent(NULL, true, false, NULL); 
     hthread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL); 
     _OutputDebugString("D3DManager: thread created handle %x\n", hthread); // my wrapper around OutputDebugString 

    } 

    D3DManager::~D3DManager() 
    { 
     stop(); 
     HRESULT hr = WaitForSingleObject(hthread, 1000); 
     if (hr == WAIT_TIMEOUT) { 
      TerminateThread(hthread, 0); 
      release_d3d(); 
     } 
     CloseHandle(exitev); 
    } 

    unsigned int __stdcall D3DManager::thread(void *) 
    { 
     create_d3d9(); 
     while(WAIT_TIMEOUT == WaitForSingleObject(exitev, 500)) { 
      d3.lock(); 
      HRESULT hr = g_d3ddev->TestCooperativeLevel(); 
      switch(hr) { 
       case S_OK: 
         break; 
       case D3DERR_DEVICENOTRESET : 
         // Fill DISPLAYPARAMETERS 
         g_d3ddev->Reset(); 
         break; 
       default: 
         break; 
      } 
      d3.unlock(); 
     } 

    ///////// This text is never seen 

     OutputDebugString("D3dManagert exit from while loop\n"); 

    //////// 
     release_d3d(); 
     _endthreadex(0); 
     return 0; 
    } 

答えて

0

はなぜストップオブジェクトの上に待機しているし、その後、合図場合、まだコードの本体を実行しますか?お試しください

while(WAIT_TIMEOUT==WaitForSingleObject(exitev, 500){ 
.. 
} 

また、私はすべてのことを分かりません!exit_signal()とexit_mutexは何ですか?あなたはミューテックスが必要なのですか?それとも、シグナルを送るイベントがあるときにexitブール値が必要ですか?停止以外の理由でイベントを通知するコードがいくつかありますか? WFSO - 'WaitForSignleObject'をタイプミングしたので、実際のコードを投稿していないことがわかりました。

「if(hr == WAIT_ABANDONED)」のいずれかではありません。私はスレッドが終了するのを待つことはほとんどないので、スレッドハンドルで待機しているときにその戻り値が生成されたかどうかはわかりません。

+0

はい、そうだと思いますが、コードを単純化してexit_mutexとexit_flagを取り除くことができます。 – wl2776

+0

WAIT_ABANDONEDは、ミューテックスで待機中でも発生します。したがって、明らかに2つのエラーがあります。私は実際のコードを投稿しましたが、そのすべてがコピーされ貼り付けられたわけではありません。手で入力しました:) – wl2776

0

exit_signal()は値をコピーしますが、返さないことがわかります。同期されたコードブロックから抜け出し、exit_signal()がfalseを返すと変数exit_flagが変更される可能性があります。

+0

Oups、はい、あなたは正しいです。とにかく、私はもうこれを必要としないので、この機能を削除しました。修正されたコードは質問の一番下にあります – wl2776

関連する問題