C++ library series -- in the MFC multiple-thread environment, how to quit worker
In the MFC environment, normally, thread should be launched with AfxBeginThread for taking usage of MFC multiple-thread mechanism; In such mechanism, those datastructures, such as AFX_MODULE_STATE, would be used by MFC framework to maintain related thread information. It runs well when threads, launched with AfxBeginThread, quit before the main thread, which is responsible for initializing C run-time, but if such main thread quit before any other thread launched by AfxBeginThread, the current application would crash.
Such crash comes from the _afxThreadData (CThreadSlotData* _afxThreadData, which is defined in AFXTLS.cpp as global data structure) has been destructed while the main thread quits and it will invoke related function to clean up global data structures, including _afxThreadData definitely.Consequently, serious developer should prepare for such case (other worker thread quits before main thread).The reasonable resolve for such issue, would ensure any other threads should quit before the main thread..h file/////////////////////////////////////////////////////////////////////////////// CSafeEnterLeaveThread threadclass CSafeEnterLeaveThread : public CWinThread{DECLARE_DYNCREATE(CSafeEnterLeaveThread)protected:CSafeEnterLeaveThread(); // protected constructor used by dynamic creation// Attributespublic:// Operationspublic:// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CSafeEnterLeaveThread)public:virtual BOOL InitInstance();virtual int ExitInstance();//}}AFX_VIRTUAL// Implementationprotected:virtual ~CSafeEnterLeaveThread();// Generated message map functions//{{AFX_MSG(CSafeEnterLeaveThread)// NOTE - the ClassWizard will add and remove member functions here.//}}AFX_MSGDECLARE_MESSAGE_MAP()};.cpp file/////////////////////////////////////////////////////////////////////////////// CSafeEnterLeaveThreadIMPLEMENT_DYNCREATE(CSafeEnterLeaveThread, CWinThread)CSafeEnterLeaveThread::CSafeEnterLeaveThread(){}CSafeEnterLeaveThread::~CSafeEnterLeaveThread(){}BOOL CSafeEnterLeaveThread::InitInstance(){// TODO: perform and per-thread initialization hereASSERT(this->m_hThread);CMainApp::RegisterMFCThread(this->m_hThread);return TRUE;}int CSafeEnterLeaveThread::ExitInstance(){// TODO: perform any per-thread cleanup hereASSERT(this->m_hThread);CMainApp::UnRegisterMFCThread(this->m_hThread);return CWinThread::ExitInstance();}BEGIN_MESSAGE_MAP(CSafeEnterLeaveThread, CWinThread)//{{AFX_MSG_MAP(CSafeEnterLeaveThread)// NOTE - the ClassWizard will add and remove mapping macros here.//}}AFX_MSG_MAPEND_MESSAGE_MAP()And in the CMainApp,set<HANDLE> g_ThreadHandleSet;HANDLE g_ThreadHandleArray[MAXIMUM_WAIT_OBJECTS];CCriticalSection g_csGlobalData;void CAccgbApp::CheckAllOtherMFCThreadsLeave(){int count = g_ThreadHandleSet.size();if (count == 0) return;set<HANDLE>::iterator it;int idx = 0;for (it = g_ThreadHandleSet.begin(); it != g_ThreadHandleSet.end() && idx < MAXIMUM_WAIT_OBJECTS; it++, idx++){g_ThreadHandleArray[idx] = *it;}if (count > idx) count = idx;::WaitForMultipleObjects(count, g_ThreadHandleArray, TRUE, INFINITE);}void CAccgbApp::CleanupGlobalData(){g_csGlobalData.Lock();g_ThreadHandleSet.empty();g_csGlobalData.Unlock();}BOOL CAccgbApp::RegisterMFCThread(HANDLE hThread){if (hThread == NULL) return FALSE;g_csGlobalData.Lock();if (g_ThreadHandleSet.find(hThread) == g_ThreadHandleSet.end())g_ThreadHandleSet.insert(hThread);g_csGlobalData.Unlock();return TRUE;}void CAccgbApp::UnRegisterMFCThread(HANDLE hThread){if (hThread == NULL) return;g_csGlobalData.Lock();if (g_ThreadHandleSet.find(hThread) != g_ThreadHandleSet.end())g_ThreadHandleSet.erase(hThread);g_csGlobalData.Unlock();}摘自 唐亮的个人技术博客
补充:软件开发 , C++ ,