0

I'm developing an ActiveX video player. It is in-process component in a DLL. I'm using Visual Studio 2010.

I need it to have a separate thread, which would start once, when the component is loaded, create Direct3D9 object and Direct3D9 device, then stop on the component unloading and destroy these objects. While the component is running I'd like this thread to periodically call TestCooperativeLevel and reset D3D device if needed.

I'm doing this since the client application can create several instances of my player, but it is strongly recommended to have only one instance of D3D9 object and device.

I've declared a class with static methods and members, whose constructor calls _beginthreadex() and starts the thread.

Here are the code excerpts (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;
    }

My component is embedded in the WindowsForms form, writtent in C#.

The problem is when I close the form, the thread is terminated inside while loop and never gets to the code after it. I've never seen the text from OutputDebugString, the release_d3d() is also never called, and I see a lot of messages from d3d debug about memory leak. If I set a breakpoint, it is never hit.

All I see is the message:

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

When I set up a breakpoint in the destructor, I get it hit, but after the messages about video memory leaks.

I've also enabled debug break on C++ Exceptions and Win32 Exception in the Studio, but none were triggered.

Update. Have read in the MSDN that all threads are terminated, when any of them calls exit, _exit, or abort or ExitProcess and tried stting in the constructor atexit handler:

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

Still no luck. release_d3d is called after I've got messages about video memory leak. Moreover I've got exception fault.

Update 2.

Here is the edited code

// .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;
    }
wl2776
  • 4,099
  • 4
  • 35
  • 77

2 Answers2

0

Why wait on the stop object and then, if signaled, still perform the body of the code? Try

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

also, I'm not sure what all that !exit_signal() and exit_mutex is for? Why do you need a mutex, or, for that matter, an exit boolean when you already have an event to signal? Is there some more code that signals the event for some other reason than stopping? I notice that you have typo'd the WFSO - 'WaitForSignleObject', so you have not posted your real code.

Not sue about 'if (hr == WAIT_ABANDONED)' either. I hardly ever wait for threads to terminate and so I don't know for sure if/why that return is made when waiting on a thread handle.

Martin James
  • 24,453
  • 3
  • 36
  • 60
  • Yes, seems you're right, I can simplify my code and get rid of exit_mutex and exit_flag. – wl2776 Apr 11 '12 at 07:33
  • WAIT_ABANDONED also is resulted when waitning on a mutex. So, there are clearly 2 errors. I've posted a real code, but not all of it was copied+pasted, I've typed that by hands :) – wl2776 Apr 11 '12 at 07:47
0

I see that your exit_signal() copies the value but does not return it. There can be chances that the variable exit_flag is changed after you get out of the synchronized block of code and your exit_signal() returns false.

IamShifu
  • 43
  • 5
  • Oups, yes, you're right. Anyway, I've removed this function, as I don't need it anymore. Corrected code is on the bottom of the question – wl2776 Apr 11 '12 at 08:00