Member 13919032 Ответов: 0

Я использовал shared_ptr для управления объектом потока событий пользователя , но блок без выхода


Здесь определяется поток:
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

и WndProc определяется здесь:
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;
}

если я прокомментирую обратный вызов WM_DESTROY msg, он будет заблокирован при выходе из основного цикла.
Главная функция здесь:
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;
}

кто-нибудь поможет мне объяснить это?

Что я уже пробовал:

Я проверил идентификатор потока ,который вызывает деструкт потока событий пользователя, и обнаружил, что есть 2 потока, вызывающих его дважды.
Почему? В чем проблема?

0 Ответов