酷知百科網

位置:首頁 > 遊戲數碼 > 電腦

MFC多線程編的可能

電腦3.03W

之所以是“可能”,因爲這裏有個重點就是臨時對象是HWND操作的封裝,不是視窗類的封裝。因此所有的HWND臨時對象都是CWnd的實例,即使上面強行轉換爲CAbcDialog*也依舊是CWnd*,所以在ASSERT_VALID裏調用CAbcDialog::AssertValid時,其定義了一些附加檢查,則可能發現這是一個CWnd的實例而非一個CAbcDialog實例,導致斷言失敗。因此應將CAbcDialog全部換成CWnd,這下雖然不斷言失敗了,但依舊錯誤(先不提pDialog->m_Data怎麼辦),因爲臨時對象是HWND操作的封裝,而不幸的是UpdateData只是MFC自己提供的一個對話框數據交換的機制(DDX)的操作,其不是透過向HWND發送消息來實現的,而是透過虛函數機制。因此在UpdateData中調用實例的DoDataExchange將不能調用CAbcDialog::DoDataExchange,而是調用CWnd::DoDataExchange,因此將不發生任何事。

步驟/方法

(01)因此合理(並不一定最好)的解決方法是向CAbcDialog的實例發送一個消息,而透過一箇中間變量(如一全局變量)來傳遞數據,而不是使用CAbcDialog::m_Data。當然,如果數據少,比如本例,就應該將數據作爲消息參數進行傳遞,減少代碼的複雜性;數據多則應該透過全局變量傳遞,減少了緩衝的管理費用。修改後如下:#define AM_DATANOTIFY ( WM_USER + 1 )static DWORD g_Data = 0;DWORD WINAPI ThreadProc( void *pData ) // 線程函數(比如用於從COM口獲取數據)BEGIN_MESSAGE_MAP( CAbcDialog, CDialog )…ON_MESSAGE( AM_DATANOTIFY, OnDataNotify )…END_MESSAGE_MAP()BOOL CAbcDialog::OnInitDialog(){CDialog::OnInitDialog();// 其他初始化代碼CreateThread( NULL, 0, ThreadProc, m_hWnd, 0, NULL ); // 創建線程return TRUE;}LRESULT CAbcDialog::OnDataNotify( WPARAM /* wParam */, LPARAM /* lParam */ ){UpdateData( FALSE );return 0;}void CAbcDialog::DoDataExchange( CDataExchange *pDX ){CDialog::DoDataExchange( pDX );DDX_Text( pDX, IDC_EDIT1, g_Data );}

MFC多線程編的可能

(02)注意事項“線程安全”是一個什麼概念?以前常聽高手告誡MFC對象不要跨線程使用,因爲MFC不是線程安全的。比如CWnd對象不要跨線程使用,可以用視窗句柄(HWND)代替。CSocket/CAsyncSocket對象不要跨線程使用,用SOCKET句柄代替.那麼到底什麼是線程安全呢?什麼時候需要考慮?如果程序涉及到多線程的話,就應該考慮線程安全問題。比如說設計的接口,將來需要在多線程環境中使用,或者需要跨線程使用某個對象時,這個就必須考慮了。關於線程安全也沒什麼權威定義。在這裏我只說說我的理解:所提供的接口對於線程來說是原子操作或者多個線程之間的切換不會導致該接口的執行結果存在二義性,也就是說我們不用考慮同步的問題。一般而言“線程安全”由多線程對共享資源的訪問引起。如果調用某個接口時需要我們自己採取同步措施來保護該接口訪問的共享資源,則這樣的接口不是線程安全的和STL都不是線程安全的. 怎樣才能設計出線程安全的類或者接口呢?如果接口中訪問的數據都屬於私有數據,那麼這樣的接口是線程安全的.或者幾個接口對共享數據都是隻讀操作,那麼這樣的接口也是線程安全的.如果多個接口之間有共享數據,而且有讀有寫的話,如果設計者自己採取了同步措施,調用者不需要考慮數據同步問題,則這樣的接口是線程安全的,否則不是線程安全的。

MFC多線程編的可能 第2張

(03)多線程的程序設計應該注意些什麼呢1、儘量少的使用全局變量、static變量做共享數據,儘量使用參數傳遞對象。被參數傳遞的對象,應該只包括必需的成員變量。所謂必需的成員變量,就是必定會被多線程操作的。很多人圖省事,會把this指針(可能是任意一個對象指針)當作線程參數傳遞,致使線程內部有過多的操作權限,對this中的參數任意妄爲。整個程序由一個人完成,可能會非常注意,不會出錯,但只要一轉手,程序就會面目全非。當兩個線程同時操作一個成員變量的時候,程序就開始崩潰了,更糟的是,這種錯誤很難被重現。(我就在鬱悶這個問題,我們是幾個人,把程序編成debug版,經過數天使用,才找到錯誤。而找到錯誤只是開始,因爲你要證明這個bug被修改成功了,也非常困難。)其實,線程間數據交互大多是單向的,在線程回調函數入口處,儘可能的將傳入的數據備份到局部變量中(當然,用於線程間通訊的變量不能這麼處理),以後只對局部變量做處理,可以很好的解決這種問題。2、在MFC中請慎用線程。因爲MFC的框架假定你的消息處理都是在主線程中完成的。首先視窗句柄是屬於線程的,如果擁有視窗句柄的線程退出了,如果另一個線程處理這個視窗句柄,系統就會出現問題。而MFC爲了避免這種情況的發生,使你在子線程中調用消息(視窗)處理函數時,就會不停的出Assert錯誤,煩都煩死你。典型的例子就時CSocket,因爲CSocket是使用了一個隱藏視窗實現了假阻塞,所以不可避免的使用了消息處理函數,如果你在子線程中使用CSocket,你就可能看到assert的彈出了。3、不要在不同的線程中同時註冊COM組件。兩個線程,一個註冊, , , ; 而另一個則註冊, , , ,結果死鎖發生了,分別死在FreeLibrary和DllRegisterServer,因爲這8個ocx是用MFC中做的,也可能是MFC的Bug,但DllRegisterServer卻死在GetModuleFileName裏,而GetModuleFileName則是個API唉!如果有過客看到,恰巧又知道其原因,請不吝賜教。4、不要把線程搞的那麼複雜。很多初學者,恨不能用上線程相關的所有的函數,這裏互斥,那裏等待,一會兒起線程,一會兒關線程的,比起goto語句有過之而無不及。好的多線程程序,應該是儘量少的使用線程。這句話怎麼理解吶,就是說盡量統一一塊數據共享區存放數據隊列,工作子線程從隊列中取數據,處理,再放回數據,這樣纔會模組化,對象化;而不是每個數據都起一個工作子線程處理,處理完了就關閉,寫的時候雖然直接,等維護起來就累了。

MFC多線程編的可能 第3張
標籤:多線程 MFC