0

ActiveX ビデオ プレーヤーを開発しています。DLL のインプロセス コンポーネントです。Visual Studio 2010 を使用しています。

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

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

_beginthreadex()コンストラクターがスレッドを呼び出して開始する静的メソッドとメンバーを持つクラスを宣言しました。

コードの抜粋を次に示します (エラーあり)。

// .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# で書かれた WindowsForms フォームに埋め込まれています。

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

私が見るのはメッセージだけです:

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

デストラクタにブレークポイントを設定するとヒットしますが、ビデオ メモリ リークに関するメッセージの後に発生します。

Studio で C++ 例外と Win32 例外のデバッグ ブレークも有効にしましたが、いずれもトリガーされませんでした。

アップデート。exitMSDN で、スレッドのいずれかが、_exit、またはabortまたはを呼び出し、コンストラクターハンドラーExitProcessで stting を試行すると、すべてのスレッドが終了することを読みました。atexit

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

まだ運がありません。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;
    }
4

2 に答える 2

0

停止オブジェクトを待ってから、シグナルが送信された場合でもコードの本体を実行するのはなぜですか? 試す

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

また、 !exit_signal() と exit_mutex が何のためにあるのかわかりませんか? 通知するイベントが既にあるのに、なぜミューテックス、またはさらに言えば終了ブール値が必要なのですか? 停止以外の理由でイベントを通知するコードは他にありますか? WFSO - 'WaitForSignleObject' のタイプミスに気がついたので、実際のコードを投稿していません。

「if (hr == WAIT_ABANDONED)」についても訴えません。スレッドが終了するのを待つことはめったにないので、スレッドハンドルを待っているときにそのリターンが行われるかどうか、またはその理由がわかりません。

于 2012-04-11T07:26:27.157 に答える
0

あなたの exit_signal() は値をコピーしますが、値を返しません。コードの同期ブロックから出た後に変数 exit_flag が変更され、exit_signal() が false を返す可能性があります。

于 2012-04-11T07:48:08.410 に答える