分类:
2010-12-08 18:24:45
1临时对象的处理
在2.4节就曾经提到了临时对象,现在是深入了解它们的时候了。
1. 临时对象指MFC对象,是MFC或者程序员使用FromHandle或者SelectObject等从一个Windows对象句柄创建的对应的MFC对象。
2. 在模块-线程状态中,临时MFC对象的映射是和永久映射分开保存的。
3. 临时MFC对象在使用完毕后由MFC框架自动删除,MFC在线程的Idle处理中删除本线程的临时MFC对象,为了防止并发修改,通过线程状态m_nTempMapLock(等于0,可以修改,大于0,等待)来同步。所以,临时MFC对象不能保存备用。
2 状态对象的删除和销毁
至此,本章讨论了MFC的线程局部存储机制,MFC状态的定义、实现和用途。在程序或者DLL退出之前,模块状态被销毁;在线程退出时,线程状态被销毁。状态对象被销毁之前,它活动期间所动态创建的对象被销毁,动态分配的内存被释放。
先解释几个函数:
AfxTermExtensionModule(HANDLE hInstanceOfDll,BOOL bAll);
若bAll为真,则该函数销毁本模块(hInstanceOfDll标识的模块)的模块状态的m_libraryList列表中所有动态分配的CDynLinkLibrary对象,否则,该函数清理本DLL动态分配的CDynLinkLibrary对象,并调用AfxTerLocalData释放本DLL模块为当前线程的线程局部变量分配的堆空间。
AfxTermLocalData(HANDLE hInstance, BOOL bAll);
若bAll为真,则删除MFC线程局部存储的所有槽的指针所指的对象,也就是销毁当前线程的全部局部变量,释放为这些线程局部变量分配的内存;否则,仅仅删除、清理当前线程在hInstance表示的DLL模块中创建的线程局部变量。
参与清理工作的函数有多种、多个,下面结合具体情况简要描述它们的作用。
(1)对动态链接到MFC DLL的应用程序
动态链接到MFC DLL的应用程序退出时,将在DllMain和RawDllMain处理进程分离时清理状态对象,该DllMain和RawDllMain是核心MFC DLL的入口和出口,在DLLINIT.CPP文件中实现,和进程分离时完成如下动作:
DllMain调用AfxTermExtensionModule(coreDll)清理核心MFC DLL的模块状态;调用AfxTermExtensionModule(coreDll, TRUE)清理OLE私有的模块状态;调用AfxTermLocalData(NULL, TRUE)释放本进程或者线程所有的局部变量。
RawDllMain在DllMain之后调用,它调用AfxTlsRealease;AfxTlsRealease减少对_afxThreadData的引用计数,如果引用数为零,则调用对应的CThreadSlotData析构函数清理_afxThreadData所指对象。
(2)对静态链接到MFC DLL的应用程序
如果是静态链接到MFC DLL的应用程序,由于RawDllMain和DllMain不起作用,将由一个静态变量析构时完成状态的清除:
有一个AFX_TERM_APP_STATE类型的静态变量,在程序结束时将被销毁,导致析构函数被调用,析构函数完成以下动作:
调用AfxTermLocalData(NULL, TRUE)释放本进程(主线程)的所用局部数据。
(3)对于动态链接到MFC DLL的规则DLL
对于动态链接到MFC DLL的规则DLL,将在RawDllMain和DllMain中清理状态对象。这两个函数在DllModule.cpp中定义,是规则DLL的入口和出口。当和进程分离时,分别有如下动作:
DllMain清除该模块的模块-线程状态中的所有临时映射,清除临时MFC对象;调用AfxWinTerm;调用AfxTermExtensionModule(controlDLL, TRUE),释放本DLL模块状态m_libraryList中的所有CDynLinkLibrary对象。
RawDllMain设置线程状态的模块状态指针,使它指向线程状态的m_PrevModuleState所指状态。
(4)对于静态链接到MFC DLL的DLL
对于静态链接到MFC DLL的DLL,只有DllMain会被调用,执行以下动作:
清除该模块的模块-线程状态中的所有临时映射,清除临时MFC对象;调用AfxWinTerm;调用AfxTermLocalData(hInstance, TRUE)清理本DLL模块的当前线程的线程局部数据。
另外,它定义一个_AFX_TERM_DLL_STATE类型的静态变量,在DLL退出时该变量被销毁,导致其析构函数被调用。析构函数完成如下动作:
调用AfxTermateLocalData(NULL, TRUE);调用AfxCriticlTerm结束关键变量;调用AfxTlsRealease。
(5)线程终止时
当使用AFxBeginThread创建的线程终止时,将调用AfxTermThread(HANDLE hInstance)作结束线程的清理工作(参数为NULL):销毁临时MFC对象,销毁本线程的线程局部变量,等等。
另外,当DLL模块和AfxBeginThread创建的线程分离时,也调用AfxTermThread(hInstance),参数是模块的句柄,销毁临时MFC对象,销毁本线程在本DLL创建的线程局部变量,等等。所以,AfxTermThread可能被调用两次。
最后,CThreadLocal和CProcessLocal的实例将被销毁,析构函数被调用:如果MFC线程局部存储空间的槽m_nSlot所指的线程局部对象还没有销毁,则销毁它。
_afxThreadData在MFC DLL的RawDllMain或者随着_AFX_TERM_APP_STATE析构函数的调用,_afxThreadData所指对象被销毁。_afxThreadData所指对象销毁之后,所有的状态相关的内存都被释放。