第九章 MFC的狀態(tài)_第1頁(yè)
第九章 MFC的狀態(tài)_第2頁(yè)
第九章 MFC的狀態(tài)_第3頁(yè)
第九章 MFC的狀態(tài)_第4頁(yè)
第九章 MFC的狀態(tài)_第5頁(yè)
已閱讀5頁(yè),還剩12頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第九章 MFC的狀態(tài)    MFC的狀態(tài) MFC定義了多種狀態(tài)信息,這里要介紹的是模塊狀態(tài)、進(jìn)程狀態(tài)、線程狀態(tài)。這些狀態(tài)可以組合在一起,例如MFC句柄映射就是模塊和線程局部有效的,屬于模塊-線程狀態(tài)的一部分。模塊狀態(tài) 這里模塊的含義是:一個(gè)可執(zhí)行的程序或者一個(gè)使用MFC DLL的DLL,比如一個(gè)OLE控件就是一個(gè)模塊。一個(gè)應(yīng)用程序的每一個(gè)模塊都有一個(gè)狀態(tài),模塊狀態(tài)包括這樣一些信息:用來(lái)加載資源的 Windows實(shí)例句柄、指向當(dāng)前CWinApp或者CWinThread對(duì)象的指針、OLE模塊的引用計(jì)數(shù)、Windows對(duì)象與相應(yīng)的MFC對(duì)象

2、之間的映射。只有單一模塊的應(yīng)用程序的狀態(tài)如圖9-1所示。m_pModuleState 指針是線程對(duì)象的成員變量,指向當(dāng)前模塊狀態(tài)信息(一個(gè)AFX_MODULE_STATE結(jié)構(gòu)變量)。當(dāng)程序運(yùn)行進(jìn)入某個(gè)特定的模塊時(shí),必須保證當(dāng)前使用的模塊狀態(tài)是有效的模塊狀態(tài)是這個(gè)特定模塊的模塊狀態(tài)。所以,每個(gè)線程對(duì)象都有一個(gè)指針指向有效的模塊狀態(tài),每當(dāng)進(jìn)入某個(gè)模塊時(shí)都要使它指向有效模塊狀態(tài),這對(duì)維護(hù)應(yīng)用程序全局狀態(tài)和每個(gè)模塊狀態(tài)的完整性來(lái)說(shuō)是非常重要的。為了作到這一點(diǎn),每個(gè)模塊的所有入口點(diǎn)有責(zé)任實(shí)現(xiàn)模塊狀態(tài)的切換。模塊的入口點(diǎn)包括:DLL的輸出函數(shù);OLE/COM界面的成員函數(shù);窗口過(guò)程。在講述窗口過(guò)程和動(dòng)態(tài)鏈

3、接到MFC DLL的規(guī)則DLL時(shí),曾提到了語(yǔ)句AFX_MANAGE_STATE(AfxGetStaticModuleState( ),它就是用來(lái)在入口點(diǎn)切換模塊狀態(tài)的。其實(shí)現(xiàn)機(jī)制將在后面9.4.1節(jié)講解。多個(gè)模塊狀態(tài)之間切換的示意圖如圖9-2所示。圖9-2中,m_pModuleState總是指向當(dāng)前模塊的狀態(tài)。模塊、進(jìn)程和線程狀態(tài)的數(shù)據(jù)結(jié)構(gòu) MFC定義了一系列類或者結(jié)構(gòu),通過(guò)它們來(lái)實(shí)現(xiàn)狀態(tài)信息的管理。這一節(jié)將描述它們的關(guān)系,并逐一解釋它們的數(shù)據(jù)結(jié)構(gòu)、成員函數(shù)等。層次關(guān)系 圖9-3顯示了線程狀態(tài)、模塊狀態(tài)、線程-模塊狀態(tài)等幾個(gè)類的層次關(guān)系:線程狀態(tài)用類_AFX_THREAD_

4、STATE描述,模塊狀態(tài)用類AFX_MODULE_STATE描述,模塊-線程狀態(tài)用類AFX_MODULE_THREAD_STATE描述。這些類從類CNoTrackObject派生。進(jìn)程狀態(tài)類用_AFX_BASE_MODULE_STATE描述,從模塊狀態(tài)類AFX_MODULE_STATE派生。進(jìn)程狀態(tài)是了一個(gè)可以獨(dú)立執(zhí)行的MFC應(yīng)用程序的模塊狀態(tài)。還有其他狀態(tài)如DLL的模塊狀態(tài)等也從模塊狀態(tài)類_AFX_MODULE_STATE派生。圖9-4顯示了這幾個(gè)類的交互關(guān)系。從圖9-4可以看出:首先,每個(gè)線程有一個(gè)線程狀態(tài),線程狀態(tài)的指針m_pModuleState和m_pPreModuleState分別

5、指向線程當(dāng)前運(yùn)行模塊的狀態(tài)或前一運(yùn)行模塊的狀態(tài);其次,每一個(gè)模塊狀態(tài)都有一個(gè)線程局部的變量用來(lái)存儲(chǔ)模塊-線程狀態(tài)。下面各小節(jié)列出狀態(tài)信息管理所涉及的各個(gè)類的定義。CNoTrackObject類 在圖9-3中, CnoTrackObject是根類,所有狀態(tài)類都是從它這里派生的,其定義如下:class CNoTrackObjectpublic:void* PASCAL operator new(size_t nSize);void PASCAL operator delete(void*);#if defined(_DEBUG) && !defined(_AFX_NO_D

6、EBUG_CRT)void* PASCAL operator new(size_t nSize, LPCSTR, int);#endifvirtual CNoTrackObject() ;該類的析構(gòu)函數(shù)是虛擬函數(shù);而且,CNoTrackObject重載new操作符用來(lái)分配內(nèi)存,重載delete操作符號(hào)用來(lái)釋放內(nèi)存,內(nèi)部通過(guò)LocalAlloc/LocalFree提供了一個(gè)低層內(nèi)存分配器(Low_level alloctor)。AFX_MODULE_STATE類 AFX_MODULE_STATE類的定義如下:/ AFX_MODULE_STATE (global data for a m

7、odule)class AFX_MODULE_STATE : public CNoTrackObjectpublic:#ifdef _AFXDLLAFX_MODULE_STATE(BOOL bDLL,WNDPROC pfnAfxWndProc,DWORD dwVersion);AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc,DWORD dwVersion,BOOL bSystem);#elseAFX_MODULE_STATE(BOOL bDLL);#endifAFX_MODULE_STATE();CWinApp* m_pCurrentWinA

8、pp;HINSTANCE m_hCurrentInstanceHandle;HINSTANCE m_hCurrentResourceHandle;LPCTSTR m_lpszCurrentAppName;BYTE m_bDLL;/ TRUE if module is a DLL, FALSE if it is an EXE/TRUE if module is a "system" module, FALSE if notBYTE m_bSystem;BYTE m_bReserved2; / padding/Runtime class data:#ifdef _AFXDLLC

9、RuntimeClass* m_pClassInit;#endifCTypedSimpleList<CRuntimeClass*> m_classList;/ OLE object factories#ifndef _AFX_NO_OLE_SUPPORT#ifdef _AFXDLLCOleObjectFactory* m_pFactoryInit;#endifCTypedSimpleList<COleObjectFactory*> m_factoryList;#endif/ number of locked OLE objectslong m_nObjectCount;

10、BOOL m_bUserCtrl;/ AfxRegisterClass and AfxRegisterWndClass dataTCHAR m_szUnregisterList4096;#ifdef _AFXDLLWNDPROC m_pfnAfxWndProc;DWORD m_dwVersion; / version that module linked against#endif/ variables related to a given process in a module/ (used to be AFX_MODULE_PROCESS_STATE)#ifdef _AFX_OLD_EXC

11、EPTIONS/ exceptionsAFX_TERM_PROC m_pfnTerminate;#endifvoid (PASCAL *m_pfnFilterToolTipMessage)(MSG*, CWnd*);#ifdef _AFXDLL/ CDynLinkLibrary objects (for resource chain)CTypedSimpleList<CDynLinkLibrary*> m_libraryList;/ special case for MFCxxLOC.DLL (localized MFC resources)HINSTANCE m_appLangD

12、LL;#endif#ifndef _AFX_NO_OCC_SUPPORT/ OLE control container managerCOccManager* m_pOccManager;/ locked OLE controlsCTypedSimpleList<COleControlLock*> m_lockList;#endif#ifndef _AFX_NO_DAO_SUPPORT_AFX_DAO_STATE* m_pDaoState;#endif#ifndef _AFX_NO_OLE_SUPPORT/ Type library cachesCTypeLibCache m_ty

13、peLibCache;CMapPtrToPtr* m_pTypeLibCacheMap;#endif/ define thread local portions of module stateTHREAD_LOCAL(AFX_MODULE_THREAD_STATE, m_thread);從上面的定義可以看出,模塊狀態(tài)信息分為如下幾類:模塊信息,資源信息,對(duì)動(dòng)態(tài)鏈接到MFC DLL的支持信息,對(duì)擴(kuò)展DLL的支持信息,對(duì)DAO的支持信息,對(duì)OLE的支持信息,模塊-線程狀態(tài)信息。模塊信息包括實(shí)例句柄、資源句柄、應(yīng)用程序名稱、指向應(yīng)用程序的指針、是否為DLL模塊、模塊注冊(cè)的窗口類,等等。其中,成員變量

14、m_fRegisteredClasses、m_szUnregisterList曾經(jīng)在討論MFC的窗口注冊(cè)時(shí)提到過(guò)它們的用處。在“#ifdef _AFXDLL#endif”條件編譯范圍內(nèi)的是支持MFC DLL的數(shù)據(jù);在“#ifndef _AFX_NO_OLE_SUPPOR#endif”條件編譯范圍內(nèi)的是支持OLE的數(shù)據(jù);在“#ifndef _AFX_NO_OCC_SUPPOR#endif”條件編譯范圍內(nèi)的是支持OLE控件的數(shù)據(jù);在“#ifndef _AFX_NO_DAO_SUPPORT”條件編譯范圍內(nèi)的是支持DAO的數(shù)據(jù)。THREAD_LOCAL宏定義了線程私有的模塊-線程類型的變量m_thre

15、ad。_AFX_BASE_MODULE_STATE 該類定義如下:class _AFX_BASE_MODULE_STATE : public AFX_MODULE_STATEpublic:#ifdef _AFXDLL_AFX_BASE_MODULE_STATE() : AFX_MODULE_STATE(TRUE,AfxWndProcBase, _MFC_VER)#else_AFX_BASE_MODULE_STATE() : AFX_MODULE_STATE(TRUE)#endif ;由定義可見(jiàn),該類沒(méi)有在_AFX_MODULE_STATE類的基礎(chǔ)上增加數(shù)據(jù)。它類用來(lái)實(shí)現(xiàn)一個(gè)MFC應(yīng)用

16、程序模塊的狀態(tài)信息。_AFX_THREAD_STATE 該類定義如下:class _AFX_THREAD_STATE : public CNoTrackObjectpublic:_AFX_THREAD_STATE();virtual _AFX_THREAD_STATE();/ override for m_pModuleState in _AFX_APP_STATEAFX_MODULE_STATE* m_pModuleState;AFX_MODULE_STATE* m_pPrevModuleState;/ memory safety pool for temp mapsvoid* m

17、_pSafetyPoolBuffer; / current buffer/ thread local exception contextAFX_EXCEPTION_CONTEXT m_exceptionContext;/ CWnd create, gray dialog hook, and other hook dataCWnd* m_pWndInit;CWnd* m_pAlternateWndInit; / special case commdlg hookingDWORD m_dwPropStyle;DWORD m_dwPropExStyle;HWND m_hWndInit;BOOL m_

18、bDlgCreate;HHOOK m_hHookOldCbtFilter;HHOOK m_hHookOldMsgFilter;/ other CWnd modal dataMSG m_lastSentMsg; / see CWnd:WindowProcHWND m_hTrackingWindow; / see CWnd:TrackPopupMenuHMENU m_hTrackingMenu;TCHAR m_szTempClassName96; / see AfxRegisterWndClassHWND m_hLockoutNotifyWindow; / see CWnd:OnCommandBO

19、OL m_bInMsgFilter;/ other framework modal dataCView* m_pRoutingView; / see CCmdTarget:GetRoutingViewCFrameWnd*m_pRoutingFrame;/see CmdTarget:GetRoutingFrame/ MFC/DB thread-local dataBOOL m_bWaitForDataSource;/ common controls thread stateCToolTipCtrl* m_pToolTip;CWnd* m_pLastHit; / last window to ow

20、n tooltipint m_nLastHit; / last hittest codeTOOLINFO m_lastInfo; / last TOOLINFO structureint m_nLastStatus; / last flyby status messageCControlBar* m_pLastStatus; / last flyby status control bar/ OLE control thread-local dataCWnd* m_pWndPark; / "parking space" windowlong m_nCtrlRef; / ref

21、erence count on parking windowBOOL m_bNeedTerm; / TRUE if OleUninitialize needs to be called;從定義可以看出,線程狀態(tài)的成員數(shù)據(jù)分如下幾類:指向模塊狀態(tài)信息的指針,支持本線程的窗口創(chuàng)建的變量,MFC命令和消息處理用到的信息,處理工具條提示信息(tooltip)的結(jié)構(gòu),和處理OLE相關(guān)的變量,等等。AFX_MODULE_THREAD_STATE 該類定義如下:/ AFX_MODULE_THREAD_STATE (local to thread *and* module)class AFX_MOD

22、ULE_THREAD_STATE : public CNoTrackObjectpublic:AFX_MODULE_THREAD_STATE();virtual AFX_MODULE_THREAD_STATE();/ current CWinThread pointerCWinThread* m_pCurrentWinThread;/ list of CFrameWnd objects for threadCTypedSimpleList<CFrameWnd*> m_frameList;/ temporary/permanent map stateDWORD m_nTempMapL

23、ock; / if not 0, temp maps lockedCHandleMap* m_pmapHWND;CHandleMap* m_pmapHMENU;CHandleMap* m_pmapHDC;CHandleMap* m_pmapHGDIOBJ;CHandleMap* m_pmapHimageLIST;/ thread-local MFC new handler (separate from C-runtime)_PNH m_pfnNewHandler;#ifndef _AFX_NO_SOCKET_SUPPORT/ WinSock specific thread stateHWND

24、m_hSocketWindow;CMapPtrToPtr m_mapSocketHandle;CMapPtrToPtr m_mapDeadSockets;CPtrList m_listSocketNotifications;#endif;模塊-線程狀態(tài)的數(shù)據(jù)成員主要有:指向當(dāng)前線程對(duì)象(CWinThread對(duì)象)的指針m_pCurrentWinThread;當(dāng)前線程的框架窗口對(duì)象(CFrameWnd對(duì)象)列表m_frameList(邊框窗口在創(chuàng)建時(shí)(見(jiàn)圖5-8)把自身添加到m-frameList中,銷毀時(shí)則刪除掉,通過(guò)列表m_frameList可以遍歷模塊所有的邊框窗口);new操作的例外處理

25、函數(shù)m_pfnNewHandler;臨時(shí)映射鎖定標(biāo)識(shí)m_nTempMapLock,防止并發(fā)修改臨時(shí)映射。系列Windows對(duì)象-MFC對(duì)象的映射,如m_pmapHWND等。這些數(shù)據(jù)成員都是線程和模塊私有的。下一節(jié)討論MFC如何通過(guò)上述這些類來(lái)實(shí)現(xiàn)其狀態(tài)的管理。線程局部存儲(chǔ)機(jī)制和狀態(tài)的實(shí)現(xiàn) MFC實(shí)現(xiàn)線程、模塊或者線程-模塊私有狀態(tài)的基礎(chǔ)是MFC的線程局部存儲(chǔ)機(jī)制。MFC定義了CThreadSlotData類型的全局變量_afxThreadData來(lái)為進(jìn)程的線程分配線程局部存儲(chǔ)空間:CThreadSlotData* _afxThreadData;在此基礎(chǔ)上,MFC定義了變量_afxTh

26、readState來(lái)管理線程狀態(tài),定義了變量_afxBaseModuleState來(lái)管理進(jìn)程狀態(tài)。THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afxBaseModuleState)對(duì)于每個(gè)THREAD_LOCAL宏定義的變量,進(jìn)程的每個(gè)線程都有自己獨(dú)立的拷貝,這個(gè)變量在不同的線程里頭可以有不同的取值。對(duì)于每個(gè)PROCESS_LOCAL宏定義的變量,每個(gè)進(jìn)程都有自己獨(dú)立的拷貝,這個(gè)變量在不同的進(jìn)程里頭可以有不同的取值。分別解釋這三個(gè)變量。CThreadSlotData

27、和_afxThreadData CThreadSlotData的定義 以Win32線程局部存儲(chǔ)機(jī)制為基礎(chǔ),MFC設(shè)計(jì)了類CThreadSlotData來(lái)提供管理線程局部存儲(chǔ)的功能,MFC應(yīng)用程序使用該類的對(duì)象全局變量_afxThreadData來(lái)管理本進(jìn)程的線程局部存儲(chǔ)。CThreadSlotData類的定義如下:class CThreadSlotDatapublic:CThreadSlotData();/Operationsint AllocSlot();void FreeSlot(int nSlot);void* GetValue(int nSlot);void Set

28、Value(int nSlot, void* pValue);/ delete all values in process/threadvoid DeleteValues(HINSTANCE hInst, BOOL bAll = FALSE);/ assign instance handle to just constructed slotsvoid AssignInstance(HINSTANCE hInst);/ ImplementationDWORD m_tlsIndex;/ used to access system thread-local storageint m_nAlloc;

29、/ number of slots allocated (in UINTs)int m_nRover; / (optimization) for quick finding of free slotsint m_nMax; / size of slot table below (in bits)CSlotData* m_pSlotData; / state of each slot (allocated or not)/list of CThreadData structuresCTypedSimpleList<CThreadData*> m_list;CRITICAL_SECTI

30、ON m_sect;/ special version for threads only!void* GetThreadValue(int nSlot);void* PASCAL operator new(size_t, void* p) return p; void DeleteValues(CThreadData* pData, HINSTANCE hInst);CThreadSlotData();通過(guò)TLS索引m_tlsIndex,CThreadSlotData對(duì)象(_afxThreadData)為每一個(gè)線程分配一個(gè)線程私有的存儲(chǔ)空間并管理該空間。它把這個(gè)空間劃分為若干個(gè)槽,每個(gè)槽放一個(gè)

31、線程私有的數(shù)據(jù)指針,這樣每個(gè)線程就可以存放任意個(gè)線程私有的數(shù)據(jù)指針。CThreadSlotData的一些數(shù)據(jù)成員 在CThreadSlotData類的定義中所涉及的類或者結(jié)構(gòu)定義如下:(1)m_sectm_sect是一個(gè)關(guān)鍵段變量,在_afxThreadData創(chuàng)建時(shí)初始化。因?yàn)開(kāi)afxThreadData是一個(gè)全局變量,所以必須通過(guò)m_sect來(lái)同步多個(gè)線程對(duì)該變量的并發(fā)訪問(wèn)。(2)m_nAlloc和m_pSlotDatam_nAlloc表示已經(jīng)分配槽的數(shù)目,它代表了線程局部變量的個(gè)數(shù)。每一個(gè)線程局部變量都對(duì)應(yīng)一個(gè)槽,每個(gè)槽對(duì)應(yīng)一個(gè)線程局部變量。槽使用CSlotData類來(lái)管理。C

32、SlotData的定義如下:struct CSlotDataDWORD dwFlags; / slot flags (allocated/not allocated)HINSTANCE hInst; / module which owns this slot;該結(jié)構(gòu)用來(lái)描述槽的使用:域dwFlags表示槽的狀態(tài),即被占用或者沒(méi)有;域hInst表示使用該槽的模塊的句柄。m_pSlotData表示一個(gè)CSlotData類型的數(shù)組,用來(lái)描述各個(gè)槽。該數(shù)組通過(guò)成員函數(shù)AllocSlot和FreeSlot來(lái)動(dòng)態(tài)地管理,見(jiàn)圖9-6。(3)m_list先討論CThreadData 類。CThreadData

33、定義如下:struct CThreadData : public CNoTrackObjectCThreadData* pNext; / required to be member of CSimpleListint nCount; / current size of pDataLPVOID* pData; / actual thread local data (indexed by nSlot);該結(jié)構(gòu)用來(lái)描述CThreadSlotData為每個(gè)線程管理的線程局部空間:域pNext把各個(gè)線程的CThreadData項(xiàng)目鏈接成一個(gè)表,即把各個(gè)線程的線程私有空間鏈接起來(lái);域nCount表示域pD

34、ata的尺寸,即存儲(chǔ)了多少個(gè)線程私有數(shù)據(jù);pData表示一個(gè)LPVOID類型的數(shù)組,數(shù)組中的每一個(gè)元素保存一個(gè)指針,即線程私有數(shù)據(jù)指針,該指針指向一個(gè)在堆中分配的真正存儲(chǔ)線程私有數(shù)據(jù)的地址。數(shù)組元素的個(gè)數(shù)和槽的個(gè)數(shù)相同,每個(gè)線程局部變量(THREAD_LOCAL定義的變量)都有一個(gè)對(duì)應(yīng)的槽號(hào),用該槽號(hào)作為下標(biāo)來(lái)引用pData。m_list表示一個(gè)CThreadData類型的指針數(shù)組,數(shù)組中的各項(xiàng)指向各個(gè)線程的線程私有空間,每個(gè)線程在數(shù)組中都有一個(gè)對(duì)應(yīng)項(xiàng)。該數(shù)組通過(guò)GetValue、SetValue、DeleteValues等成員函數(shù)來(lái)管理,見(jiàn)圖9-6。_afxThreadData _

35、afxThreadData僅僅定義為一個(gè)CThreadSlotData類型的指針,所指對(duì)象在第一次被引用時(shí)創(chuàng)建,在此之前該指針為空。下文_afxThreadData含義是它所指的對(duì)象。圖9-5、9-6圖解了MFC的線程局部存儲(chǔ)機(jī)制的實(shí)現(xiàn)。圖9-5表示_afxTheadData使用TLS技術(shù)負(fù)責(zé)給進(jìn)程分配一個(gè)TLS索引,然后使用TLS索引為進(jìn)程的每一個(gè)線程分配線程局部存儲(chǔ)空間。圖9-6表示每個(gè)線程的的局部存儲(chǔ)空間可以分多個(gè)槽,每個(gè)槽可以放一個(gè)線程私有的數(shù)據(jù)指針。_afxThreadData負(fù)責(zé)給線程局部變量分配槽號(hào)并根據(jù)槽號(hào)存取數(shù)據(jù)。圖的左半部分描述了管理槽的m_pSlotData及類CSlot

36、Data的結(jié)構(gòu),右半部分描述了管理MFC線程私有空間的m_list及類CThreadData的結(jié)構(gòu)。結(jié)合圖9-6,對(duì)MFC線程局部存儲(chǔ)機(jī)制總結(jié)如下:每個(gè)線程局部變量(宏THREAD_LOCAL定義)占用一個(gè)槽,并有一個(gè)槽號(hào)。 每個(gè)線程都有自己的MFC局部存儲(chǔ)空間(下文多次使用“線程的MFC局部存儲(chǔ)空間”,表示和此處相同的概念)。 通過(guò)TLS索引得到的是一個(gè)指針P1,它指向線程的MFC局部存儲(chǔ)空間。 通過(guò)指針P1和線程局部變量在空間所占用的槽號(hào),得到該槽所存儲(chǔ)的線程私有的數(shù)據(jù)指針,即真正的線程私有數(shù)據(jù)的地址P2; 從地址P2得到數(shù)據(jù)D。 這個(gè)過(guò)程

37、相當(dāng)于幾重間接尋址:先得到TLS線程私有數(shù)據(jù)指針,從TLS線程私有數(shù)據(jù)指針得到線程的MFC線程局部存儲(chǔ)空間,再?gòu)腗FC局部存儲(chǔ)空間的對(duì)應(yīng)槽得到一個(gè)線程私有的數(shù)據(jù)指針,從該指針得到最終的線程私有數(shù)據(jù)。如果沒(méi)有這種機(jī)制,使用Win32 TLS只要一次間接尋址:得到TLS線程私有數(shù)據(jù)指針,從該指針得到最終的線程私有數(shù)據(jù)。線程狀態(tài)_afxThreadState 從上一節(jié)知道了MFC的線程局部存儲(chǔ)機(jī)制。但有一點(diǎn)還不清楚,即某個(gè)線程局部變量所占用的槽號(hào)是怎么保存的呢?關(guān)于這點(diǎn)可從線程局部的線程狀態(tài)變量_afxThreadState的實(shí)現(xiàn)來(lái)分析MFC的作法。變量_afxThreadState的定義

38、如下:THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)THREAD_LOCAL 是一個(gè)宏,THREAD_LOCAL(class_name, ident_name)宏展開(kāi)后如下:AFX_DATADEF CThreadLocal<class_name> ident_name;這里,CThreadLocal是一個(gè)類模板,從CThreadLocalObject類繼承。CThreadLocalObject和CThreadLocal的定義如下:class CThreadLocalObjectpublic:/ AttributesCNoTrackO

39、bject* GetData(CNoTrackObject* (AFXAPI*pfnCreateObject)();CNoTrackObject* GetDataNA();/ Implementationint m_nSlot;CThreadLocalObject();CThreadLocalObject用來(lái)幫助實(shí)現(xiàn)一個(gè)線程局部的變量。成員變量m_nSlot表示線程局部變量在MFC線程局部存儲(chǔ)空間中占據(jù)的槽號(hào)。GetDataNA用來(lái)返回變量的值。GetData也可以返回變量的值,但是如果發(fā)現(xiàn)還沒(méi)有給該變量分配槽號(hào)(m_slot=0),則給它分配槽號(hào)并在線程的MFC局部空間為之分配一個(gè)槽;如果在

40、槽m_nSlot還沒(méi)有數(shù)據(jù)(為空),則調(diào)用參數(shù)pfnCreateObject傳遞的函數(shù)創(chuàng)建一個(gè)數(shù)據(jù)項(xiàng),并保存到槽m_nSlot中。template<class TYPE>class CThreadLocal : public CThreadLocalObject/ Attributespublic:inline TYPE* GetData()TYPE* pData = (TYPE*)CThreadLocalObject:GetData(&CreateObject);ASSERT(pData != NULL);return pData;inline TYPE* GetData

41、NA()TYPE* pData = (TYPE*)CThreadLocalObject:GetDataNA();return pData;inline operator TYPE*() return GetData(); inline TYPE* operator->() return GetData(); / Implementationpublic:static CNoTrackObject* AFXAPI CreateObject() return new TYPE; ;CThreadLocal模板用來(lái)聲明任意類型的線程私有的變量,因?yàn)橥ㄟ^(guò)模板可以自動(dòng)的正確的轉(zhuǎn)化(cast)指針類

42、型。程序員可以使用它來(lái)實(shí)現(xiàn)自己的線程局部變量,正如MFC實(shí)現(xiàn)線程局部的線程狀態(tài)變量和模塊-線程變量一樣。CThrealLocal的成員函數(shù)CreateObject用來(lái)創(chuàng)建動(dòng)態(tài)的指定類型的對(duì)象。成員函數(shù)GetData調(diào)用了基類CThreadLocalObject的同名函數(shù),并且把CreateObject函數(shù)的地址作為參數(shù)傳遞給它。另外,CThreadLocal模板重載了操作符號(hào)“*”、“->”,這樣編譯器將自動(dòng)地進(jìn)行有關(guān)類型轉(zhuǎn)換,例如:_AFX_THREAD_STATE *pStata = _afxThreadState是可以被編譯器接收的。現(xiàn)在回頭來(lái)看_afxThreadState的定義

43、:從以上分析可以知道,THREAD_LOCAL(class_name, ident_name)定義的結(jié)果并沒(méi)有產(chǎn)生一個(gè)名為ident_name的class_name類的實(shí)例,而是產(chǎn)生一個(gè)CThreadLocal模板類(確切地說(shuō),是其派生類)的實(shí)例,m_nSlot初始化為0。所以,_afxThreadState實(shí)質(zhì)上是一個(gè)CThreadLocal模板類的全局變量。每一個(gè)線程局部變量都對(duì)應(yīng)了一個(gè)全局的CThreadLoacl模板類對(duì)象,模板對(duì)象的m_nSlot記錄了線程局部變量對(duì)象的槽號(hào)。進(jìn)程模塊狀態(tài)afxBaseModuleState 進(jìn)程模塊狀態(tài)定義如下:PROCESS_LOCAL(

44、_AFX_BASE_MODULE_STATE, _afxBaseModuleState)表示它是一個(gè)_AFX_BASE_MODULE_STATE類型的進(jìn)程局部(process local)的變量。進(jìn)程局部變量的實(shí)現(xiàn)方法主要是為了用于Win32s下。在Win32s下,一個(gè)DLL模塊如果被多個(gè)應(yīng)用程序調(diào)用,它將讓這些程序共享它的全局?jǐn)?shù)據(jù)。為了DLL的全局?jǐn)?shù)據(jù)一個(gè)進(jìn)程有一份獨(dú)立的拷貝,MFC設(shè)計(jì)了進(jìn)程私有的實(shí)現(xiàn)方法,實(shí)際上就是在進(jìn)程的堆(Heap)中分配全局?jǐn)?shù)據(jù)的內(nèi)存空間。在Win32下,DLL模塊的數(shù)據(jù)和代碼被映射到調(diào)用進(jìn)程的虛擬空間,也就是說(shuō),DLL定義的全局變量是進(jìn)程私有的;所以進(jìn)程局部變量的

45、實(shí)現(xiàn)并不為Win32所關(guān)心。但是,不是說(shuō)afxBaseModuleState不重要,僅僅是采用PROCESS_LOCAL技術(shù)聲明它是進(jìn)程局部變量不是很必要了。PROCESS_LOCAL(class_name, ident_name)宏展開(kāi)后如下:AFX_DATADEF CProcessLocal<class_name> ident_name;這里,CProcessLocal是一個(gè)類模板,從CProcessLocalObject類繼承。CProcessLocalObject和CProcessLocal的定義如下:class CProcessLocalObjectpublic:/ At

46、tributesCNoTrackObject* GetData(CNoTrackObject* (AFXAPI*pfnCreateObject)();/ ImplementationCNoTrackObject* volatile m_pObject;CProcessLocalObject();template<class TYPE>class CProcessLocal : public CProcessLocalObject/ Attributespublic:inline TYPE* GetData()TYPE* pData =(TYPE*)CProcessLocalObje

47、ct:GetData(&CreateObject);ASSERT(pData != NULL);return pData;inline TYPE* GetDataNA() return (TYPE*)m_pObject; inline operator TYPE*() return GetData(); inline TYPE* operator->() return GetData(); / Implementationpublic:static CNoTrackObject* AFXAPI CreateObject() return new TYPE; ;類似于線程局部對(duì)象,

48、每一個(gè)進(jìn)程局部變量都有一個(gè)對(duì)應(yīng)的全局CProcessLocal模板對(duì)象。狀態(tài)對(duì)象的創(chuàng)建 狀態(tài)對(duì)象的創(chuàng)建過(guò)程 回顧前一節(jié)的三個(gè)定義:CThreadSlotData* _afxThreadData;THREAD_LOCAL(_AFX_THREAD_STATE, _afxThreadState)PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, _afxBaseModuleState)第一個(gè)僅僅定義了一個(gè)指針;第二和第三個(gè)定義了一個(gè)模板類的實(shí)例。相應(yīng)的CThreadSlotData對(duì)象(全局)、_AFX_THREAD_STATE對(duì)象(線程局部)以及_AFX

49、_BASE_MODULE_STATE對(duì)象(進(jìn)程局部)并沒(méi)有創(chuàng)建。當(dāng)然,模塊狀態(tài)對(duì)象的成員模塊-線程對(duì)象也沒(méi)有被創(chuàng)建。這些對(duì)象要到第一次被訪問(wèn)時(shí),才會(huì)被創(chuàng)建,這樣做會(huì)提高加載DLL的速度。下面以一個(gè)動(dòng)態(tài)鏈接到MFC DLL的單模塊應(yīng)用程序?yàn)槔f(shuō)明這些對(duì)象的創(chuàng)建過(guò)程。當(dāng)?shù)谝淮卧L問(wèn)狀態(tài)信息時(shí),比如使用 AfxGetModuleState得到模塊狀態(tài),導(dǎo)致系列創(chuàng)建過(guò)程的開(kāi)始,如圖9-7所示。首先分析語(yǔ)句pState=_afxThreadState。如果_afxThreadData、線程狀態(tài)和模塊狀態(tài)還沒(méi)有創(chuàng)建,該語(yǔ)句可以導(dǎo)致這些數(shù)據(jù)的創(chuàng)建。pState聲明為CNoTrackObject對(duì)象的指針,_

50、afxThreadState聲明為一個(gè)模板CThreadLocal的實(shí)例,pState=_afxThreadData為什么可以通過(guò)編譯器的檢查呢?因?yàn)镃ThreadLocal模板重載了操作符“”*”和“->”,這兩個(gè)運(yùn)算返回CNoTrackObject類型的對(duì)象。回顧3.2節(jié)CThreadLocalObject、CThreadLocal的定義,這兩個(gè)操作符運(yùn)算到最后都是調(diào)用CThreadLocalObject的成員函數(shù)GetData。創(chuàng)建_afxThreadData所指對(duì)象和線程狀態(tài) CThreadLocalObject:GetData用來(lái)獲取線程局部變量(這個(gè)例子中是線程狀態(tài)

51、)的值,其參數(shù)用來(lái)創(chuàng)建動(dòng)態(tài)的線程局部變量。圖9-7的上面的虛線框表示其流程:它檢查成員變量m_nSlot是否等于0(線程局部變量是否曾經(jīng)被分配了MFC線程私有空間槽位),檢查全局變量_afxTheadData指針是否為空。如果_afxThreadData空,則創(chuàng)建一個(gè)CThreadSlotData類對(duì)象,讓_afxThreadData指向它,這樣本程序的MFC線程局部存儲(chǔ)的管理者被創(chuàng)建。如果m_nSlot等于0,則讓_afxThreadDtata調(diào)用AllocSlot分配一個(gè)槽位并把槽號(hào)保存在m_nSlot中。得到了線程局部變量(線程狀態(tài))所占用的槽位后,委托_afxThreadData調(diào)用G

52、etThreadValue(m_nSlot)得到線程狀態(tài)值(指針)。如果結(jié)果非空,則返回它;如果結(jié)果是NULL,則表明該線程狀態(tài)還沒(méi)有被創(chuàng)建,于是使用參數(shù)創(chuàng)建一個(gè)動(dòng)態(tài)的線程狀態(tài),并使用SetValue把其指針保存在槽m_nSlot中,返回該指針。創(chuàng)建模塊狀態(tài) 得到了線程狀態(tài)的值后,通過(guò)它得到模塊狀態(tài)m_pModuleState。如果m_pModuleState為空,表明該線程狀態(tài)是才創(chuàng)建的,其許多成員變量還沒(méi)有賦值,程序的進(jìn)程模塊狀態(tài)還沒(méi)有被創(chuàng)建。于是調(diào)用函數(shù)_afxBaseModule.GetData,導(dǎo)致進(jìn)程模塊狀態(tài)被創(chuàng)建。圖9-7的下面一個(gè)虛線框表示了CProcessLocal

53、Object:GetData的創(chuàng)建過(guò)程:_afxBaseModule首先檢查成員變量m_pObject是否空,如果非空就返回它,即進(jìn)程模塊狀態(tài)指針;否則,在堆中創(chuàng)建一個(gè)動(dòng)態(tài)的_AFX_BASE_MODULE_STATE對(duì)象,返回。從上述兩個(gè)GetData的實(shí)現(xiàn)可以看出,CThreadLocal模板對(duì)象負(fù)責(zé)線程局部變量的創(chuàng)建和管理(查詢,修改,刪除);CProcessLocal模板對(duì)象負(fù)責(zé)進(jìn)程局部變量的創(chuàng)建和管理(查詢,修改,刪除)。模塊-線程狀態(tài)的創(chuàng)建 模塊狀態(tài)的成員模塊-線程狀態(tài)m_thread的創(chuàng)建類似于線程狀態(tài)的創(chuàng)建:當(dāng)?shù)谝淮卧L問(wèn)m_thread所對(duì)應(yīng)的CThreadLocal

54、模板對(duì)象時(shí),給m_thread分配MFC線程局部存儲(chǔ)的私有槽號(hào)m_nSlot,并動(dòng)態(tài)地創(chuàng)建_AFX_MODULE_THREAD_STATE對(duì)象,保存對(duì)象指針在m_nSlot槽中。創(chuàng)建過(guò)程所涉及的幾個(gè)重要函數(shù)的算法 創(chuàng)建過(guò)程所涉及的幾個(gè)重要函數(shù)的算法描述如下:AllocSlot AllocSlot用來(lái)分配線程的MFC私有存儲(chǔ)空間的槽號(hào)。由于該函數(shù)要修改全局變量_afxThreadData,所以必須使用m_sect關(guān)鍵段對(duì)象來(lái)同步多個(gè)線程對(duì)該函數(shù)的調(diào)用。CThreadSlotData:AllocSlot()進(jìn)入關(guān)鍵段代碼(EnterCriticalSection(m_sect)

55、;)搜索m_pSlotData,查找空槽(SLOT)如果不存在空槽(第一次進(jìn)入時(shí),肯定不存在)分配或再分配內(nèi)存以創(chuàng)建新槽,指針m_pSlotData指向分配的地址。得到新槽(SLOT)標(biāo)志該SLOT為已用記錄最新可用的SLOT到成員變量m_nRover中。離開(kāi)關(guān)鍵段代碼(LeaveCriticalSection(m_sect);)返回槽號(hào)GetThreadValue GetThreadValue用來(lái)獲取調(diào)用線程的第slot個(gè)線程局部變量的值。每一個(gè)線程局部變量都占用一個(gè)且只一個(gè)槽位。CThreadSlotData:GetThreadValue(int slot)/得到一個(gè)CThrea

56、dData型的指針pData/pData指向MFC線程私有存儲(chǔ)空間。/m_tlsIndex在_afxThreadData創(chuàng)建時(shí)由構(gòu)造函數(shù)創(chuàng)建pData=(CThreadData*)TlsGetValue(m_tlsIndex),。如果指針空或slot>pData->nCount, 則返回空。否則,返回pDataSetValue SetValue用來(lái)把調(diào)用線程的第slot個(gè)線程局部變量的值(指針)存放到線程的MFC私有存儲(chǔ)空間的第slot個(gè)槽位。CThreadSlotData:SetValue(int slot, void *pValue)/通過(guò)TLS索引得到線程的MFC私

57、有存儲(chǔ)空間pData = (CThreadData*)TlsGetValue(m_tlsIndex)/沒(méi)有得到值或者pValue非空且當(dāng)前槽號(hào),即/線程局部變量的個(gè)數(shù)/大于使用當(dāng)前局部變量的線程個(gè)數(shù)時(shí)if (pData NULL or slot > pData->nCount && pValue!=NULL)if pData NULL /當(dāng)前線程第一次訪問(wèn)該線程局部變量創(chuàng)建一個(gè)CThreadData實(shí)例;添加到CThreadSlotData:m_list;令pData指向它;按目前為止,線程局部變量的個(gè)數(shù)為pData->pData分配或重分配內(nèi)存,用來(lái)容納指向

58、真正線程數(shù)據(jù)的指針調(diào)用TlsSetValue(pData)保存pData/把指向真正線程數(shù)據(jù)的pValue保存在pData對(duì)應(yīng)的slot中pData->pDataslot = pValue管理狀態(tài) 在描述了MFC狀態(tài)的實(shí)現(xiàn)機(jī)制之后,現(xiàn)在來(lái)討論MFC的狀態(tài)管理和相關(guān)狀態(tài)的作用。模塊狀態(tài)切換 模塊狀態(tài)切換就是把當(dāng)前線程的線程狀態(tài)的m_pModuleState指針指向即將運(yùn)行模塊的模塊狀態(tài)。MFC使用AFX_MANAGE_STATE宏來(lái)完成模塊狀態(tài)的切換,即進(jìn)入模塊時(shí)使用當(dāng)前模板的模板狀態(tài),并保存原模板狀態(tài);退出模塊時(shí)恢復(fù)原來(lái)的模塊狀態(tài)。這相當(dāng)于狀態(tài)的壓棧和出棧。實(shí)現(xiàn)原理如

59、下。先看MFC關(guān)于AFX_MANAGE_STATE的定義:#ifdef _AFXDLLstruct AFX_MAINTAIN_STATEAFX_MAINTAIN_STATE(AFX_MODULE_STATE* pModuleState);AFX_MAINTAIN_STATE();protected:AFX_MODULE_STATE* m_pPrevModuleState;/AFX_MANAGE_STATE宏的定義:#define AFX_MANAGE_STATE(p) AFX_MAINTAIN_STATE _ctlState(p);#else / _AFXDLL#define AFX_MANA

60、GE_STATE(p)#endif /!_AFXDLL如果使用MFC DLL,MFC提供類AFX_MAINTAIN_STATE來(lái)實(shí)現(xiàn)狀態(tài)的壓棧和出棧,AFX_MANAGE_SATATE宏的作用是定義一個(gè)AFX_MAINTAIN_STATE類型的局部變量_ctlState。AFX_MAINTAIN_STATE的構(gòu)造函數(shù)在其成員變量m_pPrevModuleState中保存當(dāng)前的模塊狀態(tài)對(duì)象,并把參數(shù)指定的模塊狀態(tài)設(shè)定為當(dāng)前模塊狀態(tài)。所以該宏作為入口點(diǎn)的第一條語(yǔ)句就切換了模塊狀態(tài)。在退出模塊時(shí),局部變量_ctlState將自動(dòng)地銷毀,這導(dǎo)致AFX_MAINTAIN_STATE的析構(gòu)函數(shù)被調(diào)用,析構(gòu)函數(shù)把保存在m_pPrevModuleState的狀態(tài)設(shè)置為當(dāng)前狀態(tài)。AFX_MANAGE_SATATE的參數(shù)在不同場(chǎng)合是不一樣的,例如,DLL的輸出函數(shù)使用 AFX_MANAGE_SATATE(AfxGetStaticMo

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論