Click here to Skip to main content
15,887,485 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
The Thread is defined here:
class event_handler_thread : public thread_object
{
                public:

                    enum et_state
                    {
                        uninitialized,
                        initialized,
                        failure_to_init
                    };

                    et_state status;


                    HINSTANCE hInstance;
                    HWND helper_window;
                    const TCHAR* window_class_name;
                    bool quit_windows_loop;
                    DWORD dwStyle;
                    HWND new_window;
                    bool event_thread_started;

                    std::mutex        window_table_mutex;

                    std::condition_variable et_signaler;

                    // note that this is the thread that will perform all the event
                    // processing.
                    std::thread::id event_thread_id;

                    event_handler_thread() :
                        hInstance(0),
                        helper_window(0),
                        window_class_name(TEXT ("demo window class")),//
                        quit_windows_loop(false),
                        dwStyle(0),
                        new_window(0),
                        event_thread_started(false)
                    {

                        status = uninitialized;
                    }
                    virtual ~event_handler_thread()
                    {
                std::cout << get_thread_id() <<"  - enter event_handler_thread destruct...is_live()\n";
                        if (is_alive())
                        {
                            if (PostMessage(helper_window,WM_USER+QUIT_EVENT_HANDLER_THREAD,0,0)==0)
                            {
                                std::cout << "enter event_handler_thread destruct...post failed\n";
                            }
                            else
                            {
                                // wait for the event handler thread to terminate.
                                std::cout << get_thread_id() << " --- enter event_handler_thread destruct...wait\n";
                                wait();
                            }
                        }

                    }

                    void start_event_thread ()
                     {

                        if (event_thread_started == false)
                        {
                            auto_mutex M(window_table_mutex);
                            if (event_thread_started == false)
                            {
                                event_thread_started = true;
                                // start up the event handler thread
                                start();

                                // wait for the event thread to get up and running
                                while (status == uninitialized)
                                    et_signaler.wait(M);

                                if (status == failure_to_init)
                                    std::cerr<<"Failed to start event thread";
                            }
                        }
                        }


                private:

                    void thread ()
                    {
                        event_thread_id = get_thread_id();

                        hInstance = GetModuleHandle(NULL);

                        if (hInstance == NULL)
                        {
                             std::cerr<< "Error gathering needed resources";

                            // signal that an error has occurred
                            window_table_mutex.lock();
                            status = failure_to_init;
                            et_signaler.notify_all();
                            window_table_mutex.unlock();
                            return;
                        }
                        // register the main window class
                        WNDCLASSEX     wndclass ;

                        wndclass.cbSize        = sizeof (WNDCLASSEX);
                        wndclass.style         = CS_DBLCLKS;
                        wndclass.lpfnWndProc   = WindowProcedure ;
                        wndclass.cbClsExtra    = 0 ;
                        wndclass.cbWndExtra    = 0 ;
                        wndclass.hInstance     = hInstance ;
                        wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
                        wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION) ;
                        wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
                        wndclass.hbrBackground = 0;//(HBRUSH) COLOR_BACKGROUND;
                        wndclass.lpszMenuName  = NULL ;
                        wndclass.lpszClassName = window_class_name ;

                        if (!RegisterClassEx (&wndclass))
                        {
                            std::cerr << "Error registering window class";
                            window_table_mutex.lock();
                            status = failure_to_init;
                            et_signaler.notify_all();
                            window_table_mutex.unlock();
                            return;
                        }

                        helper_window = CreateWindow(window_class_name,TEXT(""),WS_DISABLED,0,0,0,0,HWND_MESSAGE,NULL,hInstance,NULL);
                        if (helper_window == NULL)
                        {
                            std::cerr << "Error gathering needed resources";
                            // signal that an error has occurred
                            window_table_mutex.lock();
                            status = failure_to_init;
                            et_signaler.notify_all();
                            window_table_mutex.unlock();
                            return;
                        }

                        // signal that the event thread is now up and running
                        window_table_mutex.lock();
                        status = initialized;
                        et_signaler.notify_all();
                        window_table_mutex.unlock();

                        MSG msg;
                        BOOL bContinue = 0;
                        try
                        {
                            std::cout << "*******enter loop***********\n";
                            while ( (bContinue = GetMessage (&msg, NULL, 0, 0))!= 0  && quit_windows_loop == false)
                            {
                                if(bContinue==-1)
                                {
                                    abort();
                                }else
                                {
                                    TranslateMessage (&msg) ;

                                    DispatchMessage (&msg) ;
                                }

                            }
                            std::cout << "*********out loop*********\n";
                        }catch(std::system_error& e)
                        {
                            std::cerr << e.what() << std::endl;
                            abort();
                        }

                    }///end thread loop

};//end event_handle_thread

and the WndProc is defined here:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    std::shared_ptr<event_handler_thread> globals(global_data());
    auto_mutex M(globals->window_table_mutex);
    switch (message)                  /* handle the messages */
    {
        ///if I comment the below WM_DESTROY msg callback, it will block when exit the main loop.
//        case WM_DESTROY:
//            PostMessage(globals->helper_window,WM_USER+QUIT_EVENT_HANDLER_THREAD,0,0);
////            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
//            break;
        case WM_USER+QUIT_EVENT_HANDLER_THREAD:
            globals->quit_windows_loop = true;
            PostQuitMessage (0);

            break;
       case WM_USER+DESTROY_WINDOW:
            DestroyWindow((HWND)wParam);
            return 0;
        case WM_USER+CREATE_WINDOW:
            {
                TCHAR nothing[] = TEXT("");
                globals->new_window = CreateWindowEx (
                               0,                   /* Extended possibilites for variation */
                               globals->window_class_name,         /* Classname */
                               _T("Demo Windows App"),       /* Title Text */
                               WS_OVERLAPPEDWINDOW, /* default window */
                               CW_USEDEFAULT,       /* Windows decides the position */
                               CW_USEDEFAULT,       /* where the window ends up on the screen */
                               544,                 /* The programs width */
                               375,                 /* and height in pixels */
                               NULL,        /* The window is a child-window to desktop */
                               NULL,                /* No menu */
                               globals->hInstance,       /* Program Instance handler */
                               NULL                 /* No Window Creation data */
                               );
                if(globals->new_window) ShowWindow(globals->new_window,SW_SHOW);
            }

             return 0;
        case WM_CLOSE:
            PostMessage(globals->helper_window,WM_USER+DESTROY_WINDOW,(WPARAM)globals->new_window,0);
            return 0;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

if I comment the WM_DESTROY msg callback, it will block when exit the main loop.
The main func is here:
int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    std::shared_ptr<event_handler_thread> globals(global_data());
    std::cout << "press \na - create new window \n0 - destroy new window \ne - exit \nother - continue\n";
    bool quit = false;
    char in = 0;
    while(!quit)
    {
        in = getchar();
        switch(in)
        {
        case 'a':
            PostMessage(globals->helper_window,WM_USER+CREATE_WINDOW,0,0);
            break;
        case '0':
            PostMessage(globals->helper_window,WM_USER+DESTROY_WINDOW,WPARAM(globals->new_window),0);
            break;
        case 'e':
            quit =true;
            break;
        default:
            continue;
        }
    }

    return 0;
}

anyone help me to explain it?

What I have tried:

I have checked the thread id which call the destruct of the user event thread ,found there are 2 thread called it twice.
Why? What's problem?
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900