1. 程式人生 > >MFC中跨執行緒UpdateData(FALSE)報錯 ASSERT FAILD問題

MFC中跨執行緒UpdateData(FALSE)報錯 ASSERT FAILD問題

文章來自:http://hi.baidu.com/yu_xiyan/item/27f82bf1a1cc0813d7ff8c8c

MFC程式,在給控制元件關聯的變數賦值後,需要呼叫UpdateData(FALSE)後才能更新到介面,但是有時候卻報錯:

斷言巨集失敗,在wincore.cpp的如下位置:
  CObject* p=NULL;
  if(pMap)
  {
   ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
     (p = pMap->LookupTemporary(m_hWnd)) != NULL);

  }
  ASSERT((CWnd*)p == this);   // must be us

這個問題其實是由於跨執行緒訪問UI元素導致的,微軟在MSDN中做了如下描述:

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的UI執行緒是執行緒相關的,每個視窗的HandleMap是儲存在建立UI那個執行緒的堆疊裡面的(thread-local-storage (TLS) ),所以,你要是在另一個執行緒裡面通過某種方式呼叫UI的UpdateData(FALSE)函式,他將無法正確執行。

知道了原因就好辦事了,下面提供兩種解決方法:

1、通過GetDlgItem(IDC_XXX)取得控制元件後SetWindowText()

    這種方式之所以能得逞,是因為呼叫SetWindowText 會導致 WM_SETTEXT被髮送給目標窗體,由訊息機制負責處理:
    ctrlDlg->GetDlgItem(IDC_EDIT19)->SetWindowText(A2W(pData));

2、自定義一個訊息,將Update訊息傳送到UI執行緒,在UI執行緒的對話方塊中處理訊息,自己執行UpdateData(FALSE)函式的呼叫。

申明:如果未加轉載說明,本文即為原創文章

————————————————————-

以下來自csdn
===================arthur======
在MFC中,user控制代碼和gdi控制代碼等是對應著一組物件(並不是所有控制代碼),它們是通過對映關係儲存在一個叫做“模組執行緒狀態”裡面的,這個“模組執行緒狀態”是屬本地執行緒所擁有的,所以如果在其它的執行緒中查詢控制代碼對應的物件指標是找不到指定的永久物件指標的,而維護這些控制代碼與物件指標的對映關係的,就是靠CHandleMap型別,其中樓主所說的
afxMapHWND()
是去取當前執行緒狀態中的當前模組狀態裡面的當前模組執行緒狀態中所儲存的視窗控制代碼與其物件對映的
CHandleMap型別的指標,在這個執行緒中沒有一次去建立這個對映的指標時,使用者如果呼叫了afxMapHWND()那麼它就返回NULL,這時ASSERT(pMap!=NULL)就會現現斷言失敗,在DEBUG下面當然會跳出錯誤了。