這是其實是我在寫多線程的過程中遇到的一個問題。
開始計划的是在一個線程中通過Create和ShowWindow彈出一個對話框,但是偶爾會出錯。跟蹤發現問題是發生在Create函數中。
#ifdef _DEBUG void CWnd::AssertValid() const { if (m_hWnd == NULL) return; // null (unattached) windows are valid // check for special wnd??? values ASSERT(HWND_TOP == NULL); // same as desktop if (m_hWnd == HWND_BOTTOM) ASSERT(this == &CWnd::wndBottom); else if (m_hWnd == HWND_TOPMOST) ASSERT(this == &CWnd::wndTopMost); else if (m_hWnd == HWND_NOTOPMOST) ASSERT(this == &CWnd::wndNoTopMost); else { // should be a normal window ASSERT(::IsWindow(m_hWnd)); // should also be in the permanent or temporary handle map CHandleMap* pMap = afxMapHWND(); ASSERT(pMap != NULL); CObject* p; // 在下面一句出錯 ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL || (p = pMap->LookupTemporary(m_hWnd)) != NULL); ASSERT((CWnd*)p == this); // must be us // Note: if either of the above asserts fire and you are // writing a multithreaded application, it is likely that // you have passed a C++ object from one thread to another // and have used that object in a way that was not intended. // (only simple inline wrapper functions should be used) // // In general, CWnd objects should be passed by HWND from // one thread to another. The receiving thread can wrap // the HWND with a CWnd object by using CWnd::FromHandle. // // It is dangerous to pass C++ objects from one thread to // another, unless the objects are designed to be used in // such a manner. } }
下面的英文的大意是說:C++中在線程間傳遞對象是不安全的。原因有:
1、 mfc的大多數類不是線程安全的,調用傳入對象的成員函數可能不會報錯,但是未必能達到程序預定的功能!
2、 mfc與界面有關的類,其大多數成員方法都是通過sendmessage實現的,如果消息處理函數本身不是線程安全的,你從工作線程中調用這些方法遲早會同你界面線程的用戶消息響應發生沖突;
3、對於CWnd相關的類,即使傳入窗口句柄,有時操作也會引起異常(ASSERT異常):通過句柄獲取窗口對象並且調用其成員函數或者成員變量!因為該對象是臨時對象,訪問其成員變量沒有意義,訪問其成員函數可能會拋出異常!
最后是通過自定義消息響應函數的機制來實現的。
在對話框類的頭文件里加上
#define WM_MY_MESSAGE WM_USER+100
在它的AFX_MSG消息響應函數模塊中加上
afx_msg void OnMyMessage(WParam wParam,LParam lParam);
在cpp文件中添加消息映射
On_Message(WM_MY_MESSAGE,OnMyMessage)
最后在加上具體的實現:
void CTestDlg ::OnMyMessage(WParam wParam,LParam lParam)
{
…………
…………
CMydlg *dlg=new CMyDlg();
dlg.Create(……);
dlg.ShowWindow(……);
}
在線程函數方面就這么寫了
void CTestDlg::OnButton1()
{
hThread=CreateThread(NULL,0,ThreadFunc,m_hWnd,0,&ThreadID);
CloseHandle(hThread);
}
DWORD WINAPI ThreadFunc(LPVOID LpParameter)
{
…………
HWND hwnd=(HWND)LpParameter;
CWnd *pWnd=CWnd::FromHandle(hwnd);
pWnd->SendMessage(WM_My_Message,(WPARAM)(&str));
}
以上的東西,有的是在網上借鑒的,有的是自己寫的。。真心喜歡那些在網絡它強大的查找功能!~也謝謝那些給我幫助的人!