Я использовал 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 потока, вызывающих его дважды.
Почему? В чем проблема?