📄 mfc中文教程(二).htm
字号:
align=justify>该结构作为线程开始函数的参数被传递给_beginthreadex函数来创建和启动线程。_beginthreadex函数是“C”的线程创建函数,具有如下原型:</P>
<P align=justify>unsigned long _beginthreadex(</P>
<P align=justify>void *security,</P>
<P align=justify>unsigned stack_size,</P>
<P align=justify>unsigned ( __stdcall *start_address )( void *
),</P>
<P align=justify>void *arglist,</P>
<P align=justify>unsigned initflag,</P>
<P align=justify>unsigned *thrdaddr );</P>
<P align=justify></P>
<P
align=justify>图8-2描述了上述过程。图中表示,_AfxThreadEntry在启动线程时,将创建本线程的线程状态,并且继承父线程的模块状态。关于MFC状态,见第9章。</P>
<P align=justify></P><IMG height=750 hspace=12
src="MFC中文教程(二).files/20050611022046331.gif" width=384 align=left>
<P align=justify></P>
<P align=justify> </P><IMG height=531 hspace=12
src="MFC中文教程(二).files/20050611022050212.gif" width=433 align=left>
<P align=justify> </P>
<P align=justify></P>
<LI><A name=_Toc445889093></A><A name=_Toc445782496></A><A
name=_Toc452640957></A><A name=_Toc457299055></A><B>线程的结束</B>
<P></P>
<P
align=justify>从图8-2可以看出,AfxEndThread用来结束调用它的线程:它将清理本线程创建的MFC对象和释放线程局部存储分配的内存空间;调用CWinThread的虚拟函数Delete;调用“C”的结束线程函数_endthreadex释放分配给线程的资源,但是不关闭线程句柄。</P>
<P
align=justify>CWinThread::Delete的缺省实现是:如果本线程的成员函数m_bDelete为TRUE,则调用“C”运算符号delete销毁MFC线程对象自身(delete
this),这将导致线程对象的析构函数被调用。若析构函数检测线程句柄非空则调用CloseHandle关闭它。</P>
<P
align=justify>通常,让m_bDelete为TRUE以便自动地销毁线程对象,释放内存空间(MFC内存对象在堆中分配)。但是,有时候,在线程结束之后(Win32线程已经不存在)保留MFC线程对象是有用的,当然程序员自己最后要记得销毁该线程对象。</P>
<P align=justify></P>
<LI><A name=_Toc445889094></A><A name=_Toc445782497></A><A
name=_Toc452640958></A><A name=_Toc457299056></A><B>实现线程的消息循环</B>
<P></P></LI></OL></OL></OL>
<P
align=justify>在MFC中,消息循环是由线程完成的。一般地,可以使用MFC缺省的消息循环(即使用函数CWindThrad::Run),但是,有些时候需要程序员自己实现一个线程的消息循环,比如在用户界面线程进行一个长时间计算处理或者等待另一个线程时。一般有如下形式:</P>
<P align=justify>while ( bDoingBackgroundProcessing) </P>
<P align=justify>{</P>
<P align=justify>MSG msg;</P>
<P align=justify>while ( ::PeekMessage( &msg, NULL,0, 0, PM_NOREMOVE )
)</P>
<P align=justify>{</P>
<DIR>
<P align=justify>if ( !PumpMessage( ) )</P>
<P align=justify>{</P>
<DIR>
<P align=justify>bDoingBackgroundProcessing = FALSE; </P>
<P align=justify>::PostQuitMessage( );</P>
<P align=justify>break;</P></DIR>
<P align=justify>}</P></DIR>
<P align=justify>}</P>
<P align=justify>// let MFC do its idle processing</P>
<P align=justify>LONG lIdle = 0;</P>
<P align=justify>while ( AfxGetApp()->OnIdle(lIdle++ ) );</P>
<P align=justify>// Perform some background processing here </P>
<P align=justify>// using another call to OnIdle</P>
<P align=justify>}</P>
<P align=justify>该段代码的解释参见图5-3对线程的Run函数的图解。</P>
<P align=justify></P>
<P
align=justify>程序员实现线程的消息循环有两个好处,一是顾及了MFC的Idle处理机制;二是在长时间的处理中可以响应用户产生的事件或者消息。</P>
<P align=justify>在同步对象上等待其他线程时,也可以使用同样的方式,只要把条件</P>
<P align=justify>bDoingBackgroundProcessing</P>
<P align=justify>换成如下形式:</P>
<P align=justify>WaitForSingObject(hHandleOfEvent,0) == WAIT_TIMEOUT</P>
<P align=justify>即可。</P>
<P align=justify>MFC处理线程和进程时还引入了一个重要的概念:状态,如线程状态(Thread
State)、进程状态(Process State)、模块状态(Module
State)等。由于这个概念在MFC中占有重要地位,涉及的内容比较多,所以专门在下一章来讲述它。</P>
<OL start=9>
<P align=justify>
<LI><A name=_Toc445889095></A><A name=_Toc445782498></A><A
name=_Toc452640959></A><A name=_Toc457299057></A><B>MFC的状态</B>
<P></P>
<P
align=justify>MFC定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合在一起,例如MFC句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。</P>
<OL>
<P align=justify>
<LI><A name=_Toc445889096></A><A name=_Toc445782499></A><A
name=_Toc452640960></A><A name=_Toc457299058></A><B>模块状态</B>
<P></P>
<P align=justify>这里模块的含义是:一个可执行的程序或者一个使用MFC
DLL的DLL,比如一个OLE控件就是一个模块。</P>
<P align=justify>一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息:用来加载资源的
Windows实例句柄、指向当前CWinApp或者CWinThread对象的指针、OLE模块的引用计数、Windows对象与相应的MFC对象之间的映射。只有单一模块的应用程序的状态如图9-1所示。</P><IMG
height=281 hspace=12 src="MFC中文教程(二).files/20050611022051357.gif"
width=181 align=left>
<P align=justify>m_pModuleState
指针是线程对象的成员变量,指向当前模块状态信息(一个AFX_MODULE_STATE结构变量)。当程序运行进入某个特定的模块时,必须保证当前使用的模块状态是有效的模块状态──是这个特定模块的模块状态。所以,每个线程对象都有一个指针指向有效的模块状态,每当进入某个模块时都要使它指向有效模块状态,这对维护应用程序全局状态和每个模块状态的完整性来说是非常重要的。为了作到这一点,每个模块的所有入口点有责任实现模块状态的切换。模块的入口点包括:DLL的输出函数;OLE/COM界面的成员函数;窗口过程。</P><IMG
height=304 hspace=12 src="MFC中文教程(二).files/20050611022051316.gif"
width=384 align=left vspace=18>
<P align=justify>在讲述窗口过程和动态链接到MFC
DLL的规则DLL时,曾提到了语句AFX_MANAGE_STATE(AfxGetStaticModuleState(
)),它就是用来在入口点切换模块状态的。其实现机制将在后面9.4.1节讲解。</P>
<P align=justify>多个模块状态之间切换的示意图如图9-2所示。</P>
<P align=justify>图9-2中,m_pModuleState总是指向当前模块的状态。</P>
<P align=justify></P>
<LI><A name=_Toc445889097></A><A name=_Toc445782500></A><A
name=_Toc452640961></A><A
name=_Toc457299059></A><B>模块、进程和线程状态的数据结构</B>
<P></P>
<P
align=justify>MFC定义了一系列类或者结构,通过它们来实现状态信息的管理。这一节将描述它们的关系,并逐一解释它们的数据结构、成员函数等。</P>
<OL>
<P align=justify>
<LI><A name=_Toc445889098></A><A name=_Toc445782501></A><A
name=_Toc452640962></A><A name=_Toc457299060></A><B>层次关系</B>
<P></P>
<P align=justify>图9-3显示了线程状态、模块状态、线程-模块状态等几个类的层次关系:</P>
<P
align=justify>线程状态用类_AFX_THREAD_STATE描述,模块状态用类AFX_MODULE_STATE描述,模块-线程状态用类AFX_MODULE_THREAD_STATE描述。这些类从类CNoTrackObject派生。进程状态类用_AFX_BASE_MODULE_STATE描述,从模块状态类AFX_MODULE_STATE派生。进程状态是了一个可以独立执行的MFC应用程序的模块状态。还有其他状态如DLL的模块状态等也从模块状态类_AFX_MODULE_STATE派生。</P>
<P align=justify>图9-4显示了这几个类的交互关系。</P>
<P align=justify></P><IMG height=177 hspace=12
src="MFC中文教程(二).files/20050611022054268.gif" width=421 align=left>
<P align=justify></P><IMG height=364 hspace=12
src="MFC中文教程(二).files/20050611022057255.gif" width=360 align=left>
<P align=justify></P>
<P
align=justify>从图9-4可以看出:首先,每个线程有一个线程状态,线程状态的指针m_pModuleState和m_pPreModuleState分别指向线程当前运行模块的状态或前一运行模块的状态;其次,每一个模块状态都有一个线程局部的变量用来存储模块-线程状态。</P>
<P align=justify>下面各小节列出状态信息管理所涉及的各个类的定义。</P>
<P align=justify></P>
<LI><A name=_Toc445889099></A><A name=_Toc445782502></A><A
name=_Toc452640963></A><A
name=_Toc457299061></A><B>CNoTrackObject类</B>
<P></P>
<P align=justify>在图9-3中, CnoTrackObject是根类,所有状态类都是从它这里派生的,其定义如下:</P>
<P align=justify>class CNoTrackObject</P>
<P align=justify>{</P>
<P align=justify>public:</P>
<P align=justify>void* PASCAL operator new(size_t nSize);</P>
<P align=justify>void PASCAL operator delete(void*);</P>
<P align=justify></P>
<P align=justify>#if defined(_DEBUG) &&
!defined(_AFX_NO_DEBUG_CRT)</P>
<P align=justify>void* PASCAL operator new(size_t nSize, LPCSTR,
int);</P>
<P align=justify>#endif</P>
<P align=justify>virtual ~CNoTrackObject() { }</P>
<P align=justify>};</P>
<P
align=justify>该类的析构函数是虚拟函数;而且,CNoTrackObject重载new操作符用来分配内存,重载delete操作符号用来释放内存,内部通过LocalAlloc/LocalFree提供了一个低层内存分配器(Low_level
alloctor)。</P>
<P align=justify></P>
<LI><A name=_Toc445889100></A><A name=_Toc445782503></A><A
name=_Toc452640964></A><A
name=_Toc457299062></A><B>AFX_MODULE_STATE类</B>
<P></P>
<P align=justify>AFX_MODULE_STATE类的定义如下:</P>
<P align=justify>// AFX_MODULE_STATE (global data for a module)</P>
<P align=justify>class AFX_MODULE_STATE : public CNoTrackObject</P>
<P align=justify>{</P>
<P align=justify>public:</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>AFX_MODULE_STATE(BOOL bDLL,WNDPROC
pfnAfxWndProc,</P>
<P align=justify>DWORD dwVersion);</P>
<P align=justify>AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc,
</P>
<P align=justify>DWORD dwVersion,BOOL bSystem);</P>
<P align=justify>#else</P>
<P align=justify>AFX_MODULE_STATE(BOOL bDLL);</P>
<P align=justify>#endif</P>
<P align=justify>~AFX_MODULE_STATE();</P>
<P align=justify></P>
<P align=justify>CWinApp* m_pCurrentWinApp;</P>
<P align=justify>HINSTANCE m_hCurrentInstanceHandle;</P>
<P align=justify>HINSTANCE m_hCurrentResourceHandle;</P>
<P align=justify>LPCTSTR m_lpszCurrentAppName;</P>
<P align=justify>BYTE m_bDLL;// TRUE if module is a DLL, FALSE if it
is an EXE</P>
<P align=justify>//TRUE if module is a "system" module, FALSE if
not</P>
<P align=justify>BYTE m_bSystem;</P>
<P align=justify>BYTE m_bReserved[2]; // padding</P>
<P align=justify></P>
<P align=justify>//Runtime class data:</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>CRuntimeClass* m_pClassInit;</P>
<P align=justify>#endif</P>
<P align=justify>CTypedSimpleList<CRUNTIMECLASS*> m_classList;</P>
<P align=justify></P>
<P align=justify>// OLE object factories</P>
<P align=justify>#ifndef _AFX_NO_OLE_SUPPORT</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>COleObjectFactory* m_pFactoryInit;</P>
<P align=justify>#endif</P>
<P align=justify>CTypedSimpleList<COLEOBJECTFACTORY*>
m_factoryList;</P>
<P align=justify>#endif</P>
<P align=justify></P>
<P align=justify>// number of locked OLE objects</P>
<P align=justify>long m_nObjectCount;</P>
<P align=justify>BOOL m_bUserCtrl;</P>
<P align=justify></P>
<P align=justify>// AfxRegisterClass and AfxRegisterWndClass
data</P>
<P align=justify>TCHAR m_szUnregisterList[4096];</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>WNDPROC m_pfnAfxWndProc;</P>
<P align=justify>DWORD m_dwVersion; // version that module linked
against</P>
<P align=justify>#endif</P>
<P align=justify></P>
<P align=justify>// variables related to a given process in a
module</P>
<P align=justify>// (used to be AFX_MODULE_PROCESS_STATE)</P>
<P align=justify>#ifdef _AFX_OLD_EXCEPTIONS</P>
<P align=justify>// exceptions</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -