一直以來,對(duì)在工作線程中更新UI這個(gè)問題沒有一個(gè)全面的認(rèn)識(shí),看到下面的文章,總算解決了心中長(zhǎng)久以來的疑惑;豁然開朗。
個(gè)人比較喜歡第一種方法。
http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/38137.html
最近寫了個(gè)代碼,在UI線程中創(chuàng)建了一個(gè)窗口,然后在工作線程中修改了這個(gè)窗口中的一些數(shù)據(jù),然后想用UpdateData(FALSE)來更新窗口的內(nèi)容,結(jié)果在Debug版本下面就出現(xiàn)了Assert報(bào)錯(cuò),說出錯(cuò)地方是wincore.cpp的888行和889行,就是這兩句
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us
我用MFC也沒有多久,也不太熟悉,翻了翻資料,在http://support.microsoft.com/default.aspx?scid=kb;en-us;147578找到一篇文章,就是說MFC窗口跨線程的問題的,大概意思就是MFC的窗口是線程相關(guān)的,每個(gè)窗口的HandleMap是儲(chǔ)存在線程相關(guān)的堆棧里面的 (thread-local-storage (TLS) ),那這樣我就理解了為什么上面兩句ASSERT會(huì)出錯(cuò)了,線程環(huán)境都切換了當(dāng)然線程堆棧的數(shù)據(jù)也就不一樣了.
這篇文章提供了兩種修改方案:
一種是用FromHandle來獲得一個(gè)CWnd*,然后再調(diào)用UpdateData,這個(gè)方案我沒有實(shí)驗(yàn)成功,結(jié)果是錯(cuò)雖然不報(bào)了,但是界面也沒有被更新.
另外一種是通過發(fā)消息的方法轉(zhuǎn)到UI線程去處理.可以在窗口映射一個(gè)消息,比如ON_MESSAGE(WM_UPDATEDATA, OnUpdateData),然后用SendMessage(WM_UPDATEDATA, FALSE)傳消息給窗口,窗口的消息處理肯定是在UI線程里面,這時(shí)候可以用
LRESULT CProtectPage::OnUpdateData(WPARAM wParam, LPARAM lParam)
{
UpdateData(wParam);
return 0;
}
來更新界面,實(shí)驗(yàn)是成功的,ASSERT就被消除了.
還是有點(diǎn)疑惑,就是剛開始直接在工作線程中調(diào)用UpdateData(FALSE)的時(shí)候,雖然有ASSERT報(bào)錯(cuò),但是結(jié)果還是正確的,似乎沒有什么影響,不知道這個(gè)ASSERT到底意味著什么?