⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mfc教程_ mfc的进程和线程.htm

📁 MFC的教程。 包括: MFC教程_ 概述.files MFC教程_ MFC和Win32.files MFC教程_ CObject类.files MFC教程_ 消息映射的实现.files
💻 HTM
📖 第 1 页 / 共 3 页
字号:
  <P></P>
  <P align=justify></P>
  <LI>使用AfxBeginThread创建MFC线程对象和Win32线程对象。如果创建线程时没有指定CREATE_SUSPENDED,则开始执行线程。 
  <P></P>
  <P align=justify></P>
  <LI>如果创建线程是指定了CREATE_SUSPENDED,则在适当的地方调用函数ResumeThread开始执行线程。 
  <P></P></LI></UL>
<OL>
  <OL>
    <OL>
      <P align=justify>
      <LI><A name=_Toc445889090></A><A name=_Toc445782493></A><A 
      name=_Toc452640954></A><A name=_Toc457299052></A><B>创建工作者线程</B> 
      <P></P>
      <P align=justify>程序员不必从CWinThread派生新的线程类,只需要提供一个控制函数,由线程启动后执行该函数。</P>
      <P 
      align=justify>然后,使用AfxBeginThread创建MFC线程对象和Win32线程对象。如果创建线程时没有指定CREATE_SUSPENDED(创建后挂起),则创建的新线程开始执行。</P>
      <P 
      align=justify>如果创建线程是指定了CREATE_SUSPENDED,则在适当的地方调用函数ResumeThread开始执行线程。</P>
      <P align=justify>虽然程序员没有从CWinThread派生类,但是MFC给工作者线程提供了缺省的CWinThread对象。</P>
      <P align=justify></P>
      <LI><A name=_Toc445889091></A><A name=_Toc445782494></A><A 
      name=_Toc452640955></A><A name=_Toc457299053></A><B>AfxBeginThread</B> 
      <P></P></LI></OL></OL></OL>
<P 
align=justify>用户界面线程和工作者线程都是由AfxBeginThread创建的。现在,考察该函数:MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,分别有如下的原型和过程:</P>
<OL>
  <P align=justify>
  <LI>用户界面线程的AfxBeginThread 
  <P></P>
  <P align=justify>用户界面线程的AfxBeginThread的原型如下:</P>
  <P align=justify>CWinThread* AFXAPI AfxBeginThread(</P>
  <P align=justify>CRuntimeClass* pThreadClass,</P>
  <P align=justify>int nPriority, </P>
  <P align=justify>UINT nStackSize, </P>
  <P align=justify>DWORD dwCreateFlags,</P>
  <P align=justify>LPSECURITY_ATTRIBUTES lpSecurityAttrs)</P>
  <P align=justify>其中:</P>
  <P align=justify>参数1是从CWinThread派生的RUNTIME_CLASS类;</P>
  <P align=justify>参数2指定线程优先级,如果为0,则与创建该线程的线程相同;</P>
  <P align=justify>参数3指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;</P>
  <P 
  align=justify>参数4是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。</P>
  <P align=justify>参数5表示线程的安全属性,NT下有用。</P>
  <P align=justify></P>
  <LI>工作者线程的AfxBeginThread 
  <P></P>
  <P align=justify>工作者线程的AfxBeginThread的原型如下:</P>
  <P align=justify>CWinThread* AFXAPI AfxBeginThread(</P>
  <P align=justify>AFX_THREADPROC pfnThreadProc, </P>
  <P align=justify>LPVOID pParam,</P>
  <P align=justify>int nPriority, </P>
  <P align=justify>UINT nStackSize, </P>
  <P align=justify>DWORD dwCreateFlags,</P>
  <P align=justify>LPSECURITY_ATTRIBUTES lpSecurityAttrs)</P>
  <P align=justify>其中:</P>
  <P align=justify>参数1指定控制函数的地址;</P>
  <P align=justify>参数2指定传递给控制函数的参数;</P>
  <P align=justify>参数3、4、5分别指定线程的优先级、堆栈大小、创建标识、安全属性,含义同用户界面线程。</P>
  <P align=justify></P>
  <LI>AfxBeginThread创建线程的流程 
  <P></P></LI></OL>
<P 
align=justify>不论哪个AfxBeginThread,首先都是创建MFC线程对象,然后创建Win32线程对象。在创建MFC线程对象时,用户界面线程和工作者线程的创建分别调用了不同的构造函数。用户界面线程是从CWinThread派生的,所以,要先调用派生类的缺省构造函数,然后调用CWinThread的缺省构造函数。图8-1中两个构造函数所调用的CommonConstruct是MFC内部使用的成员函数。</P><IMG 
height=468 hspace=12 src="MFC教程_ MFC的进程和线程.files/image140.gif" width=349 
align=left> 
<OL>
  <OL>
    <OL>
      <P align=justify>
      <LI><A name=_Toc445889092></A><A name=_Toc445782495></A><A 
      name=_Toc452640956></A><A 
      name=_Toc457299054></A><B>CreateThread和_AfxThreadEntry</B> 
      <P></P>
      <P 
      align=justify>MFC使用CWinThread::CreateThread创建线程,不论对工作者线程或用户界面线程,都指定线程的入口函数是_AfxThreadEntry。_AfxThreadEntry调用AfxInitThread初始化线程。</P>
      <P 
      align=justify>CreateThread和_AfxThreadEntry在线程的创建过程中使用同步手段交互等待、执行。CreateThread由创建线程执行,_AfxThreadEntry由被创建的线程执行,两者通过两个事件对象(hEvent和hEvent2)同步:</P>
      <P 
      align=justify>在创建了新线程之后,创建线程将在hEvent事件上无限等待直到新线程给出创建结果;新线程在创建成功或者失败之后,触发事件hEvent让父线程运行,并且在hEven2上无限等待直到父线程退出CreateThread函数;父线程(创建线程)因为hEvent的置位结束等待,继续执行,退出CreateThread之前触发hEvent2事件;新线程(子线程)因为hEvent2的置位结束等待,开始执行控制函数(工作者线程)或者进入消息循环(用户界面线程)。</P>
      <P align=justify>MFC在线程创建中使用了如下数据结构:</P>
      <P align=justify>struct _AFX_THREAD_STARTUP</P>
      <P align=justify>{</P>
      <P align=justify>//传递给线程启动的参数(IN)</P>
      <P align=justify>_AFX_THREAD_STATE* pThreadState;//父线程的线程状态</P>
      <P align=justify>CWinThread* pThread; //新创建的MFC线程对象</P>
      <P align=justify>DWORD dwCreateFlags; //线程创建标识</P>
      <P align=justify>_PNH pfnNewHandler; //新线程的句柄</P>
      <P align=justify>HANDLE hEvent; //同步事件,线程创建成功或失败后置位</P>
      <P align=justify>HANDLE hEvent2; //同步事件,新线程恢复执行后置位</P>
      <P align=justify></P>
      <P align=justify>//返回给创建线程的参数,在新线程恢复执行后赋值</P>
      <P align=justify>BOOL bError; //如果创建发生错误,TRUE</P>
      <P align=justify>};</P>
      <P 
      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教程_ MFC的进程和线程.files/image141.gif" width=384 align=left> 
      <P align=justify></P>
      <P align=justify> </P><IMG height=531 hspace=12 
      src="MFC教程_ MFC的进程和线程.files/image142.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( &amp;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()-&gt;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>
<HR>

<TABLE cellSpacing=0 cellPadding=0 width="100%" align=center border=0>
  <TBODY>
  <TR>
    <TD align=middle><A href="http://www.vczx.com/tutorial/mfc/mfc7.php" 
      target=_self>上一章</A> <A href="http://www.vczx.com/tutorial/mfc/mfc.php" 
      target=_self>回目录</A> <A href="http://www.vczx.com/tutorial/mfc/mfc9.php" 
      target=_self>下一章</A></TD></TR></TBODY></TABLE>
<P>&nbsp;</P>
<P align=justify></P></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -