2012-04-11 184 views
0

我正在開發一個ActiveX視頻播放器。它是DLL中的進程內組件。我正在使用Visual Studio 2010.我需要它有一個單獨的線程,它會在組件加載時創建一次,創建Direct3D9對象和Direct3D9設備,然後停止組件卸載並銷燬這些對象。在組件正在運行時,我希望此線程定期調用TestCooperativeLevel,並在需要時重置D3D設備。win32線程意外終止在activeX(C++)

我這樣做是因爲客戶端應用程序可以創建我的播放器的幾個實例,但強烈建議只有一個D3D9對象和設備的實例。

我已經聲明靜態方法和成員,它的構造函數調用_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; 
    } 

我的組件嵌入在WindowsForms窗體中,在C#中進行了寫入。

問題是,當我關閉窗體時,線程終止內部while循環和之後不會繼續執行代碼。我從來沒有見過OutputDebugString的文本,release_d3d()也從來沒有被調用過,並且我看到很多來自d3d調試的關於內存泄漏的消息。如果我設置了一個斷點,它永遠不會被擊中。

我看到的是消息:

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

當我設置一個斷點在析構函數,我得到它擊中,但有關視頻內存泄漏的消息後。

我還啓用了C++異常和Win32異常在Studio調試中斷,但沒有被觸發。

更新。 在MSDN讀過的所有線程終止,當其中任何一個來電exit_exitabortExitProcess並在構造atexit處理程序試圖stting:

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

回答

0

爲什麼要等待停止對象,然後,如果信號,仍然執行代碼的身體嗎?嘗試

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

也,我不知道所有的!exit_signal()和exit_mutex是?爲什麼你需要一個互斥體,或者,在這種情況下,當你已經有一個事件發出信號時,你需要一個退出布爾值?是否還有其他一些代碼可以通過其他原因發出信號而不是停止?我注意到你有錯誤的WFSO - 'WaitForSignleObject',所以你沒有發佈你的真實代碼。

不是起訴'if(hr == WAIT_ABANDONED)'。我幾乎沒有等待線程終止,所以我不確定是否/爲什麼在等待線程句柄時返回。

+0

是的,看起來你是對的,我可以簡化我的代碼並擺脫exit_mutex和exit_flag。 – wl2776 2012-04-11 07:33:22

+0

WAIT_ABANDONED也是在互斥體上等待時產生的。所以,顯然有2個錯誤。我已經發布了一個真實的代碼,但並不是所有代碼都被複制+粘貼,我用手輸入了它:) – wl2776 2012-04-11 07:47:18

0

我看到你的exit_signal()複製了這個值,但是沒有返回它。退出同步代碼塊後,可能會有變量exit_flag被更改,並且exit_signal()返回false。

+0

Oups,是的,你是對的。無論如何,我已經刪除了這個功能,因爲我不再需要它了。更正的代碼位於問題的底部 – wl2776 2012-04-11 08:00:16