Safer Timer Thread termination
-
I was experimenting on a worker thread to do a timer which posts a message each second and the thread is created in the CView constructor (MY APP is SDI) class CMyView:public CView { //consturctor ... public: static UINT RunTimer(LPVOID p); void Run(); public: volatile BOOL m_bRunTimer; //other stuff }; CMyView::CMyView() { m_bRunTimer=TRUE; //Initialize Stuff AfxBeginThread(RunTimer,this); //Get A Thread To Post A Message Every Second } the Run Timer Function is used in This Way ///////////////////////////////////////////////// UINT CMyView::RunTimer(LPVOID p) { ((CMyView*)p)->Run (); return 0; } void CMyView::Run () { while (m_bRunTimer) { ::Sleep (1000); PostMessage (UWM_TIMER_SECOND); /*Note Here that UWM_TIMER_MESSAGE IS user Defined Message*/ } } every thing works great till this point and the thread posts a message each second and the message handling is doin great the problem arises when the window(program) is closed then a debug assertion failure dialog box is displayed saying the when we are Posting a message we are posting a message to a window that no longer exists. I tried adding The line m_bRunTimer=FALSE; in ~CMyView() but no change then i wrote some code in the void CMyView::OnDestroy() { m_bRunTimer=FALSE; ::Sleep(4000);//Simply Added to Elapse the Time Slice of Main Thread CView::OnDestroy(); } After Doing i finally got safe with removing the thread and returns value i used TRACE() that my thread is safley removed and everything but i think my way of getting rid of the thread is kind of not portable and clean is there any other way that i can do this safley.
-
I was experimenting on a worker thread to do a timer which posts a message each second and the thread is created in the CView constructor (MY APP is SDI) class CMyView:public CView { //consturctor ... public: static UINT RunTimer(LPVOID p); void Run(); public: volatile BOOL m_bRunTimer; //other stuff }; CMyView::CMyView() { m_bRunTimer=TRUE; //Initialize Stuff AfxBeginThread(RunTimer,this); //Get A Thread To Post A Message Every Second } the Run Timer Function is used in This Way ///////////////////////////////////////////////// UINT CMyView::RunTimer(LPVOID p) { ((CMyView*)p)->Run (); return 0; } void CMyView::Run () { while (m_bRunTimer) { ::Sleep (1000); PostMessage (UWM_TIMER_SECOND); /*Note Here that UWM_TIMER_MESSAGE IS user Defined Message*/ } } every thing works great till this point and the thread posts a message each second and the message handling is doin great the problem arises when the window(program) is closed then a debug assertion failure dialog box is displayed saying the when we are Posting a message we are posting a message to a window that no longer exists. I tried adding The line m_bRunTimer=FALSE; in ~CMyView() but no change then i wrote some code in the void CMyView::OnDestroy() { m_bRunTimer=FALSE; ::Sleep(4000);//Simply Added to Elapse the Time Slice of Main Thread CView::OnDestroy(); } After Doing i finally got safe with removing the thread and returns value i used TRACE() that my thread is safley removed and everything but i think my way of getting rid of the thread is kind of not portable and clean is there any other way that i can do this safley.
IMO, after signalling the thread to stop you should use WaitForSingleObject.
-
I was experimenting on a worker thread to do a timer which posts a message each second and the thread is created in the CView constructor (MY APP is SDI) class CMyView:public CView { //consturctor ... public: static UINT RunTimer(LPVOID p); void Run(); public: volatile BOOL m_bRunTimer; //other stuff }; CMyView::CMyView() { m_bRunTimer=TRUE; //Initialize Stuff AfxBeginThread(RunTimer,this); //Get A Thread To Post A Message Every Second } the Run Timer Function is used in This Way ///////////////////////////////////////////////// UINT CMyView::RunTimer(LPVOID p) { ((CMyView*)p)->Run (); return 0; } void CMyView::Run () { while (m_bRunTimer) { ::Sleep (1000); PostMessage (UWM_TIMER_SECOND); /*Note Here that UWM_TIMER_MESSAGE IS user Defined Message*/ } } every thing works great till this point and the thread posts a message each second and the message handling is doin great the problem arises when the window(program) is closed then a debug assertion failure dialog box is displayed saying the when we are Posting a message we are posting a message to a window that no longer exists. I tried adding The line m_bRunTimer=FALSE; in ~CMyView() but no change then i wrote some code in the void CMyView::OnDestroy() { m_bRunTimer=FALSE; ::Sleep(4000);//Simply Added to Elapse the Time Slice of Main Thread CView::OnDestroy(); } After Doing i finally got safe with removing the thread and returns value i used TRACE() that my thread is safley removed and everything but i think my way of getting rid of the thread is kind of not portable and clean is there any other way that i can do this safley.
I was thinking that the problem could be solved with another safety check. Make sure the window exists before posting the message! if( ::IsWindow(m_hWnd) ){ PostMessage (UWM_TIMER_SECOND); } Note that you want to invoke the GLOBAL IsWindow and not the class-specific override, that is whyt he :: is in front of the function name. Now, you avoid your crash, and some other issue you might not have discovered yet. I always make sure the target window still exists before posting or sending a mesage from a different thread. Now, if you waited on an event and sets its timeout to 1000 milliseconds, you could signal the event from your main thread, and the timer thread could exit sooner (instead of always being asleep for 1 second). If you see WAIT_OBJECT_0 you exit the thread, otherwise, if it gets WAIT_TIMEOUT, you just post your message as normal. This way, your main app would not necessarily need to wait 4 seconds, it could exit immediately. Also, a s the other person suggests, you can wait on the timer thread handle in the main thread to know when the timer thread was done.