MFC應用程式中的多線程與UI視窗

來源:互聯網
上載者:User

參見: http://hi.baidu.com/winnyang/blog/item/e0925616ba82561e962b43c6.html

 

 

SUMMARY
In a multi-threaded application written using MFC, you should not pass MFC objects across thread boundaries. As a general rule, a thread should access only those MFC objects that it creates. Failure to do so may cause run-time problems including assertions or unexpected program behavior.
使用MFC編寫多線程應用程式,不能跨線程傳遞MFC對象。作為一種基本的準則,線程只允許操作由其本身建立的MFC對象。不遵守該準則將導致斷言(assertion)或者無法預知的程式行為等運行期錯誤。


MORE INFORMATION
In a Win32 process, all the threads running in the process address space can view all global and static data. A thread can use thread-local-storage (TLS) to store any thread-specific data. 
所有運行在win32進程地址空間中的線程能夠查看全域和靜態資料。線程使用“線程局部儲存(TLS)”技術來儲存跟線程相關的資料。


In a multi-threaded environment because windows are owned by threads, MFC keeps the temporary and permanent window handle map in thread local storage. The same is true for other handle maps like those for GDI objects and device contexts. Keeping the window handle maps in thread local storage ensures protection against simultaneous access by several threads. 
在多線程環境中,由於所有的視窗元素都通過線程來管理,於是MFC將暫時/永久視窗<->控制代碼映射儲存在TLS中。其他的視窗控制代碼映射以及裝置描述表也是採用類似的方法儲存。將這些視窗控制代碼映射儲存在TLS中能夠防止其他線程同時訪問這些資料。


The behavior of the functions CHandleMap::LookupPermanent() and CHandleMap::LookupTemporary() is a direct consequence of these facts. Given a window handle, these functions check the permanent and temporary window handle maps of the current thread for the existence of an associated CWnd derived MFC object. This means that if calls to these functions are made from a thread to search for MFC objects that represent windows created in other threads, these calls will fail. 
函數:CHandleMap::LookupPermanent() 和 CHandleMap::LookupTemporary()就是這種理論的直接產物。給定視窗控制代碼,這些函數通過尋找臨時以及永久的視窗控制代碼映射來獲得CWnd或者其子類對象。這就意味著如果一個線程調用這些函數來尋找其他線程的CWnd或者其子類對象,調用將失敗。


There are several functions that call CHandleMap::LookupPermanent() and CHandleMap::LookupTemporary(). CWnd::AssertValid() (and hence the macro ASSERT_VALID for a CWnd object) is one such function. This function is called to make validity checks on an object. If AssertValid() fails to find an entry for the MFC object's m_hWnd member in any of the handle maps or finds an incorrect entry, it fires an assertion. In Visual C++ 2.1, these assertions are in file Wincore.cpp, lines 797 and 798. In Visual C++ 2.2, they are in Wincore.cpp, lines 804 and 805. In Visual C++ 4.0, they are in Wincore.cpp, lines 871 and 872. 
MFC中有大量函數調用CHandleMap::LookupPermanent() and CHandleMap::LookupTemporary()。CWnd::AssertValid()就是其中一個(宏ASSERT_VALID也是一個).調用該函數來檢查對象的有效性。如果沒有發現有效CWnd對象,則會報“斷言(Assertion)”錯誤。VC2.1中,該錯誤出現在wincore.cpp, lines 797 & 798, VC2.2中,出現在wincore.cpp行804和805,VC4.0則出現在行871和872。


Calls to the ASSERT_VALID macro are sprinkled all over the MFC source code. Hence, from a particular thread, if you end up calling a function that calls ASSERT_VALID on MFC window objects that belong to some other thread, you get an assertion. If you do not get an assertion, you may still get abnormal behavior because you are not allowed to directly manipulate windows created by other threads. 
宏ASSERT_VALID的調用在MFC中相當頻繁。這樣,如果你調用該宏來驗證其他線程對象的有效性,就會出現斷言錯誤。就算不出現斷言錯誤,也會導致程式異常退出,這是因為不允許直接操作其他線程中的CWnd對象。


The correct approach in such situations is to work with window handles, not MFC objects. It is safe to pass window handles across thread boundaries. If thread A passes a window handle to thread B, then thread B can use this window handle to send or post messages to the window. When these messages are processed, you are back in the context of thread A and calls to CWnd::AssertValid() to check thread A's window handle maps will succeed. 
解決的方法是使用視窗控制代碼而不是MFC對象。線上程之間傳遞視窗控制代碼是安全的。如果線程A向線程B傳遞一個視窗控制代碼,那麼,線程B可以通過發送訊息給擁有該控制代碼的視窗對象。在處理視窗訊息時,系統已經切換到線程A。這是驗證視窗對象的有效性會成功。


In this scenario, thread B can also use the CWnd::FromHandle() function to get a temporary CWnd object which is placed in thread B's temporary handle map. However this object may be of only limited use, because in no way is it in synchronization with the MFC object existing in thread A's handle maps.
與此同時,線程B能夠調用CWnd::FromHandle()函數來獲得暫時的視窗對象,不過這一對象應該謹慎使用。因為它無法與存在於線程A視窗對象映射中的對象同步。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.