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;
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
{
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();
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";
window_table_mutex.lock();
status = failure_to_init;
et_signaler.notify_all();
window_table_mutex.unlock();
return;
}
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;
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";
window_table_mutex.lock();
status = failure_to_init;
et_signaler.notify_all();
window_table_mutex.unlock();
return;
}
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();
}
}
};
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)
{
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,
globals->window_class_name,
_T("Demo Windows App"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
544,
375,
NULL,
NULL,
globals->hInstance,
NULL
);
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:
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?