0

我正在开发一个 ActiveX 视频播放器。它是 DLL 中的进程内组件。我正在使用 Visual Studio 2010。

我需要它有一个单独的线程,它会在加载组件时启动一次,创建 Direct3D9 对象和 Direct3D9 设备,然后停止组件卸载并销毁这些对象。在组件运行时,如果需要,我希望该线程定期调用TestCooperativeLevel和重置 D3D 设备。

我这样做是因为客户端应用程序可以创建我的播放器的多个实例,但强烈建议只有一个 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 循环内终止,并且永远不会访问它之后的代码。我从未见过来自 的文本OutputDebugStringrelease_d3d()也从未调用过,而且我看到来自 d3d debug 的很多关于内存泄漏的消息。如果我设置断点,它永远不会被击中。

我看到的只是消息:

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

当我在析构函数中设置断点时,我遇到了它,但是在有关视频内存泄漏的消息之后。

我还在 Studio 中启用了 C++ 异常和 Win32 异常的调试中断,但没有触发。

更新。在 MSDN 中读到所有线程都被终止,当它们中的任何一个调用exit,_exitabortorExitProcess并尝试在构造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

我看到您的 exit_signal() 复制了该值但不返回它。在您退出同步代码块并且您的 exit_signal() 返回 false 后,变量 exit_flag 可能会发生更改。

于 2012-04-11T07:48:08.410 回答
0

为什么要在停止对象上等待,然后,如果发出信号,仍然执行代码主体?尝试

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

另外,我不确定 !exit_signal() 和 exit_mutex 是干什么用的?为什么你需要一个互斥体,或者,当你已经有一个事件要发出信号时,你需要一个退出布尔值?除了停止之外,是否还有更多代码可以出于其他原因发出事件信号?我注意到你打错了 WFSO - 'WaitForSignleObject',所以你没有发布你的真实代码。

也不起诉“如果(hr == WAIT_ABANDONED)”。我几乎从不等待线程终止,所以我不确定在等待线程句柄时是否/为什么会返回。

于 2012-04-11T07:26:27.157 回答