﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-swo2006-文章分类-线程</title><link>http://www.cppblog.com/swo2006/category/3204.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 16:05:19 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 16:05:19 GMT</pubDate><ttl>60</ttl><item><title>深入浅出Win32多线程设计之MFC的多线程[转]</title><link>http://www.cppblog.com/swo2006/articles/11378.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 17 Aug 2006 14:30:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11378.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11378.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11378.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11378.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11378.html</trackback:ping><description><![CDATA[
		<font style="font-size: 14pt;" color="#295200">
				<b>深入浅出Win32多线程设计之MFC的多线程(ZT)</b>
		</font>
		<table style="border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr>
								<td>
										<div style="margin: 15px;" id="art">
												<div>
														<a href="http://msdn2.microsoft.com/zh-cn/library/172d2hhw.aspx">http://msdn2.microsoft.com/zh-cn/library/172d2hhw.aspx</a>
												</div>
												<div>1、创建和终止线程<br /><br />　　在MFC程序中创建一个线程，宜调用AfxBeginThread函数。该函数因参数不同而具有两种重载版本，分别对应工作者线程和用户接口（UI）线程。<br /><br />　　工作者线程<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CWinThread *AfxBeginThread(<br />　AFX_THREADPROC pfnThreadProc, //控制函数<br />　LPVOID pParam, //传递给控制函数的参数<br />　int nPriority = THREAD_PRIORITY_NORMAL, //线程的优先级<br />　UINT nStackSize = 0, //线程的堆栈大小<br />　DWORD dwCreateFlags = 0, //线程的创建标志<br />　LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL //线程的安全属性<br />);</td></tr></tbody></table><br />　　工作者线程编程较为简单，只需编写线程控制函数和启动线程即可。下面的代码给出了定义一个控制函数和启动它的过程：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>//线程控制函数<br />UINT MfcThreadProc(LPVOID lpParam)<br />{<br />　CExampleClass *lpObject = (CExampleClass*)lpParam;<br />　if (lpObject == NULL || !lpObject-&gt;IsKindof(RUNTIME_CLASS(CExampleClass)))<br />　　return - 1; //输入参数非法 <br />　//线程成功启动<br />　while (1)<br />　{<br />　　...//<br />　}<br />　return 0;<br />}<br /><br />//在MFC程序中启动线程<br />AfxBeginThread(MfcThreadProc, lpObject);</td></tr></tbody></table><br />　　UI线程<br /><br />　　创建用户界面线程时，必须首先从CWinThread 派生类，并使用 DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE 宏声明此类。<br /><br />　　下面给出了CWinThread类的原型（添加了关于其重要函数功能和是否需要被继承类重载的注释）：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>class CWinThread : public CCmdTarget<br />{<br />　DECLARE_DYNAMIC(CWinThread)<br /><br />　public:<br />　　// Constructors<br />　　CWinThread();<br />　　BOOL CreateThread(DWORD dwCreateFlags = 0, UINT nStackSize = 0,<br />LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);<br /><br />　　// Attributes<br />　　CWnd* m_pMainWnd; // main window (usually same AfxGetApp()-&gt;m_pMainWnd)<br />　　CWnd* m_pActiveWnd; // active main window (may not be m_pMainWnd)<br />　　BOOL m_bAutoDelete; // enables 'delete this' after thread termination<br /><br />　　// only valid while running<br />　　HANDLE m_hThread; // this thread's HANDLE<br />　　operator HANDLE() const;<br />　　DWORD m_nThreadID; // this thread's ID<br /><br />　　int GetThreadPriority();<br />　　BOOL SetThreadPriority(int nPriority);<br /><br />　　// Operations<br />　　DWORD SuspendThread();<br />　　DWORD ResumeThread();<br />　　BOOL PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam);<br /><br />　　// Overridables<br />　　//执行线程实例初始化，必须重写<br />　　virtual BOOL InitInstance();<br /><br />　　// running and idle processing<br />　　//控制线程的函数，包含消息泵，一般不重写<br />　　virtual int Run();<br /><br />　　//消息调度到TranslateMessage和DispatchMessage之前对其进行筛选，<br />　　//通常不重写<br />　　virtual BOOL PreTranslateMessage(MSG* pMsg);<br /><br />　　virtual BOOL PumpMessage(); // low level message pump<br /><br />　　//执行线程特定的闲置时间处理，通常不重写<br />　　virtual BOOL OnIdle(LONG lCount); // return TRUE if more idle processing<br />　　virtual BOOL IsIdleMessage(MSG* pMsg); // checks for special messages<br /><br />　　//线程终止时执行清除，通常需要重写<br />　　virtual int ExitInstance(); // default will 'delete this'<br /><br />　　//截获由线程的消息和命令处理程序引发的未处理异常，通常不重写<br />　　virtual LRESULT ProcessWndProcException(CException* e, const MSG* pMsg);<br /><br />　　// Advanced: handling messages sent to message filter hook<br />　　virtual BOOL ProcessMessageFilter(int code, LPMSG lpMsg);<br /><br />　　// Advanced: virtual access to m_pMainWnd<br />　　virtual CWnd* GetMainWnd();<br /><br />　　// Implementation<br />　public:<br />　　virtual ~CWinThread();<br />　　#ifdef _DEBUG<br />　　　virtual void AssertValid() const;<br />　　　virtual void Dump(CDumpContext&amp; dc) const;<br />　　　int m_nDisablePumpCount; // Diagnostic trap to detect illegal re-entrancy<br />　　#endif<br />　　void CommonConstruct();<br />　　virtual void Delete();<br />　　// 'delete this' only if m_bAutoDelete == TRUE<br /><br />　　// message pump for Run<br />　　MSG m_msgCur; // current message<br /><br />　public:<br />　　// constructor used by implementation of AfxBeginThread<br />　　CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam);<br /><br />　　// valid after construction<br />　　LPVOID m_pThreadParams; // generic parameters passed to starting function<br />　　AFX_THREADPROC m_pfnThreadProc;<br /><br />　　// set after OLE is initialized<br />　　void (AFXAPI* m_lpfnOleTermOrFreeLib)(BOOL, BOOL);<br />　　COleMessageFilter* m_pMessageFilter;<br /><br />　protected:<br />　　CPoint m_ptCursorLast; // last mouse position<br />　　UINT m_nMsgLast; // last mouse message<br />　　BOOL DispatchThreadMessageEx(MSG* msg); // helper<br />　　void DispatchThreadMessage(MSG* msg); // obsolete<br />};<br /></td></tr></tbody></table><br />　　启动UI线程的AfxBeginThread函数的原型为：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CWinThread *AfxBeginThread(<br />　//从CWinThread派生的类的 RUNTIME_CLASS<br />　CRuntimeClass *pThreadClass, <br />　int nPriority = THREAD_PRIORITY_NORMAL, <br />　UINT nStackSize = 0, <br />　DWORD dwCreateFlags = 0,<br />　LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL<br />); </td></tr></tbody></table><br />　　我们可以方便地使用VC++ 6.0类向导定义一个继承自CWinThread的用户线程类。下面给出产生我们自定义的CWinThread子类CMyUIThread的方法。<br /><br />　　打开VC++ 6.0类向导，在如下窗口中选择Base Class类为CWinThread，输入子类名为CMyUIThread，点击"OK"按钮后就产生了类CMyUIThread。<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://yesky.anhuinews.com/imagelist/06/01/575l04oac886.jpg" border="0" /></div></td></tr></tbody></table><br />　　其源代码框架为：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>/////////////////////////////////////////////////////////////////////////////<br />// CMyUIThread thread<br /><br />class CMyUIThread : public CWinThread<br />{<br />　DECLARE_DYNCREATE(CMyUIThread)<br />　protected:<br />　　CMyUIThread(); // protected constructor used by dynamic creation<br /><br />　　// Attributes<br />　public:<br /><br />　　// Operations<br />　public:<br /><br />　　// Overrides<br />　　// ClassWizard generated virtual function overrides<br />　　//{{AFX_VIRTUAL(CMyUIThread)<br />　　public:<br />　　　virtual BOOL InitInstance();<br />　　　virtual int ExitInstance();<br />　　//}}AFX_VIRTUAL<br /><br />　　// Implementation<br />　protected:<br />　　virtual ~CMyUIThread();<br /><br />　　// Generated message map functions<br />　　//{{AFX_MSG(CMyUIThread)<br />　　　// NOTE - the ClassWizard will add and remove member functions here.<br />　　//}}AFX_MSG<br /><br />　DECLARE_MESSAGE_MAP()<br />};<br /><br />/////////////////////////////////////////////////////////////////////////////<br />// CMyUIThread<br /><br />IMPLEMENT_DYNCREATE(CMyUIThread, CWinThread)<br /><br />CMyUIThread::CMyUIThread()<br />{}<br /><br />CMyUIThread::~CMyUIThread()<br />{}<br /><br />BOOL CMyUIThread::InitInstance()<br />{<br />　// TODO: perform and per-thread initialization here<br />　return TRUE;<br />}<br /><br />int CMyUIThread::ExitInstance()<br />{<br />　// TODO: perform any per-thread cleanup here<br />　return CWinThread::ExitInstance();<br />}<br /><br />BEGIN_MESSAGE_MAP(CMyUIThread, CWinThread)<br />//{{AFX_MSG_MAP(CMyUIThread)<br />// NOTE - the ClassWizard will add and remove mapping macros here.<br />//}}AFX_MSG_MAP<br />END_MESSAGE_MAP()</td></tr></tbody></table><br />　　使用下列代码就可以启动这个UI线程：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CMyUIThread *pThread;<br />pThread = (CMyUIThread*)<br />AfxBeginThread( RUNTIME_CLASS(CMyUIThread) );</td></tr></tbody></table><br />　　另外，我们也可以不用AfxBeginThread 创建线程，而是分如下两步完成：<br /><br />　　（1）调用线程类的构造函数创建一个线程对象；<br /><br />　　（2）调用CWinThread::CreateThread函数来启动该线程。<br /><br />　　在线程自身内调用AfxEndThread函数可以终止该线程：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>void AfxEndThread(<br />　UINT nExitCode //the exit code of the thread<br />);</td></tr></tbody></table><br />　　对于UI线程而言，如果消息队列中放入了WM_QUIT消息，将结束线程。<br /><br />　　关于UI线程和工作者线程的分配，最好的做法是：将所有与UI相关的操作放入主线程，其它的纯粹的运算工作交给独立的数个工作者线程。<br /><br />　　候捷先生早些时间喜欢为MDI程序的每个窗口创建一个线程，他后来澄清了这个错误。因为如果为MDI程序的每个窗口都单独创建一个线程，在窗口进行切换的时候，将进行线程的上下文切换！</div>
												<div>2.线程间通信<br /><br />　　MFC中定义了继承自CSyncObject类的CCriticalSection
、CCEvent、CMutex、CSemaphore类封装和简化了WIN32
API所提供的临界区、事件、互斥和信号量。使用这些同步机制，必须包含"Afxmt.h"头文件。下图给出了类的继承关系：<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://yesky.anhuinews.com/imagelist/06/01/1pzf0afz2ais.jpg" border="0" /></div></td></tr></tbody></table><br />　　作为CSyncObject类的继承类，我们仅仅使用基类CSyncObject的接口函数就可以方便、统一的操作CCriticalSection 、CCEvent、CMutex、CSemaphore类，下面是CSyncObject类的原型：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>class CSyncObject : public CObject<br />{<br />　DECLARE_DYNAMIC(CSyncObject)<br /><br />　// Constructor<br />　public:<br />　　CSyncObject(LPCTSTR pstrName);<br /><br />　　// Attributes<br />　public:<br />　　operator HANDLE() const;<br />　　HANDLE m_hObject;<br /><br />　　// Operations<br />　　virtual BOOL Lock(DWORD dwTimeout = INFINITE);<br />　　virtual BOOL Unlock() = 0;<br />　　virtual BOOL Unlock(LONG /* lCount */, LPLONG /* lpPrevCount=NULL */)<br />　　{ return TRUE; }<br /><br />　　// Implementation<br />　public:<br />　　virtual ~CSyncObject();<br />　　#ifdef _DEBUG<br />　　　CString m_strName;<br />　　　virtual void AssertValid() const;<br />　　　virtual void Dump(CDumpContext&amp; dc) const;<br />　　#endif<br />　　friend class CSingleLock;<br />　　friend class CMultiLock;<br />};</td></tr></tbody></table><br />　　CSyncObject类最主要的两个函数是Lock和Unlock，若我们直接使用CSyncObject类及其派生类，我们需要非常小心地在Lock之后调用Unlock。<br /><br />　　MFC提供的另两个类CSingleLock（等待一个对象）和CMultiLock（等待多个对象）为我们编写应用程序提供了更灵活的机制，下面以实际来阐述CSingleLock的用法：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>class CThreadSafeWnd<br />{<br />　public:<br />　　CThreadSafeWnd(){}<br />　　~CThreadSafeWnd(){}<br />　　void SetWindow(CWnd *pwnd)<br />　　{<br />　　　m_pCWnd = pwnd;<br />　　}<br />　　void PaintBall(COLORREF color, CRect &amp;rc);<br />　private:<br />　　CWnd *m_pCWnd;<br />　　CCriticalSection m_CSect;<br />};<br /><br />void CThreadSafeWnd::PaintBall(COLORREF color, CRect &amp;rc)<br />{<br />　CSingleLock csl(&amp;m_CSect);<br />　//缺省的Timeout是INFINITE，只有m_Csect被激活，csl.Lock()才能返回<br />　//true，这里一直等待<br />　if (csl.Lock())<br />;<br />　{<br />　　// not necessary<br />　　//AFX_MANAGE_STATE(AfxGetStaticModuleState( ));<br />　　CDC *pdc = m_pCWnd-&gt;GetDC();<br />　　CBrush brush(color);<br />　　CBrush *oldbrush = pdc-&gt;SelectObject(&amp;brush);<br />　　pdc-&gt;Ellipse(rc);<br />　　pdc-&gt;SelectObject(oldbrush);<br />　　GdiFlush(); // don't wait to update the display<br />　}<br />}</td></tr></tbody></table><br />　　上述实例讲述了用CSingleLock对Windows GDI相关对象进行保护的方法，下面再给出一个其他方面的例子：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>int array1[10], array2[10];<br />CMutexSection section; //创建一个CMutex类的对象<br /><br />//赋值线程控制函数<br />UINT EvaluateThread(LPVOID param) <br />{<br />　CSingleLock singlelock; <br />　singlelock(&amp;section);<br /><br />　//互斥区域<br />　singlelock.Lock();<br />　for (int i = 0; i &lt; 10; i++)<br />　　array1[i] = i;<br />　singlelock.Unlock();<br />}<br />//拷贝线程控制函数<br />UINT CopyThread(LPVOID param) <br />{<br />　CSingleLock singlelock;<br />　singlelock(&amp;section);<br /><br />　//互斥区域<br />　singlelock.Lock();<br />　for (int i = 0; i &lt; 10; i++)<br />　　array2[i] = array1[i];<br />　singlelock.Unlock();<br />}<br />}<br /><br />AfxBeginThread(EvaluateThread, NULL); //启动赋值线程<br />AfxBeginThread(CopyThread, NULL); //启动拷贝线程</td></tr></tbody></table><br />　
　上面的例子中启动了两个线程EvaluateThread和CopyThread，线程EvaluateThread把10个数赋值给数组array1
[]，线程CopyThread将数组array1[]拷贝给数组array2[]。由于数组的拷贝和赋值都是整体行为，如果不以互斥形式执行代码段：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>for (int i = 0; i &lt; 10; i++)<br />array1[i] = i;</td></tr></tbody></table><br />　　和<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>for (int i = 0; i &lt; 10; i++)<br />array2[i] = array1[i];</td></tr></tbody></table><br />　　其结果是很难预料的！<br /><br />　　除了可使用CCriticalSection、CEvent、CMutex、CSemaphore作为线程间同步通信的方式以外，我们还可以利用PostThreadMessage函数在线程间发送消息：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>BOOL PostThreadMessage(DWORD idThread, // thread identifier<br />UINT Msg, // message to post<br />WPARAM wParam, // first message parameter<br />LPARAM lParam // second message parameter<br />);</td></tr></tbody></table></div>
												<div>3.线程与消息队列<br /><br />　　在WIN32中，每一个线程都对应着一个消息队列。由于一个线程可以产生数个窗口，所以并不是每个窗口都对应着一个消息队列。下列几句话应该作为"定理"被记住：<br /><br />　　"定理" 一<br /><br />　　所有产生给某个窗口的消息，都先由创建这个窗口的线程处理；<br /><br />　　"定理" 二<br /><br />　　Windows屏幕上的每一个控件都是一个窗口，有对应的窗口函数。<br /><br />　　消息的发送通常有两种方式，一是SendMessage，一是PostMessage，其原型分别为：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>LRESULT SendMessage(HWND hWnd, // handle of destination window<br />　UINT Msg, // message to send<br />　WPARAM wParam, // first message parameter<br />　LPARAM lParam // second message parameter<br />);<br />BOOL PostMessage(HWND hWnd, // handle of destination window<br />　UINT Msg, // message to post<br />　WPARAM wParam, // first message parameter<br />　LPARAM lParam // second message parameter<br />);</td></tr></tbody></table><br />　
　两个函数原型中的四个参数的意义相同，但是SendMessage和PostMessage的行为有差异。SendMessage必须等待消息被处理后
才返回，而PostMessage仅仅将消息放入消息队列。SendMessage的目标窗口如果属于另一个线程，则会发生线程上下文切换，等待另一线程
处理完成消息。为了防止另一线程当掉，导致SendMessage永远不能返回，我们可以调用SendMessageTimeout函数：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>LRESULT SendMessageTimeout(<br />　HWND hWnd, // handle of destination window<br />　UINT Msg, // message to send<br />　WPARAM wParam, // first message parameter<br />　LPARAM lParam, // second message parameter<br />　UINT fuFlags, // how to send the message<br />　UINT uTimeout, // time-out duration<br />　LPDWORD lpdwResult // return value for synchronous call<br />);</td></tr></tbody></table><br />　　4. MFC线程、消息队列与MFC程序的"生死因果"<br /><br />　　分析MFC程序的主线程启动及消息队列处理的过程将有助于我们进一步理解UI线程与消息队列的关系，为此我们需要简单地叙述一下MFC程序的"生死因果"（侯捷：《深入浅出MFC》）。<br /><br />　　使用VC++ 6.0的向导完成一个最简单的单文档架构MFC应用程序MFCThread：<br /><br />　　（1） 输入MFC EXE工程名MFCThread；<br /><br />　　（2） 选择单文档架构，不支持Document/View结构；<br /><br />　　（3） ActiveX、3D container等其他选项都选择无。<br /><br />　　我们来分析这个工程。下面是产生的核心源代码：<br /><br />　　MFCThread.h 文件<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>class CMFCThreadApp : public CWinApp<br />{<br />　public:<br />　　CMFCThreadApp();<br /><br />　　// Overrides<br />　　// ClassWizard generated virtual function overrides<br />　　//{{AFX_VIRTUAL(CMFCThreadApp)<br />　　　public:<br />　　　　virtual BOOL InitInstance();<br />　　//}}AFX_VIRTUAL<br /><br />　　// Implementation<br /><br />　public:<br />　　//{{AFX_MSG(CMFCThreadApp)<br />　　　afx_msg void OnAppAbout();<br />　　　// NOTE - the ClassWizard will add and remove member functions here.<br />　　　// DO NOT EDIT what you see in these blocks of generated code !<br />　　//}}AFX_MSG<br />　DECLARE_MESSAGE_MAP()<br />};</td></tr></tbody></table><br />　　MFCThread.cpp文件<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CMFCThreadApp theApp;<br /><br />/////////////////////////////////////////////////////////////////////////////<br />// CMFCThreadApp initialization<br /><br />BOOL CMFCThreadApp::InitInstance()<br />{<br />　…<br />　CMainFrame* pFrame = new CMainFrame;<br />　m_pMainWnd = pFrame;<br /><br />　// create and load the frame with its resources<br />　pFrame-&gt;LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,NULL);<br />　// The one and only window has been initialized, so show and update it.<br />　pFrame-&gt;ShowWindow(SW_SHOW);<br />　pFrame-&gt;UpdateWindow();<br /><br />　return TRUE;<br />}</td></tr></tbody></table><br />　　MainFrm.h文件<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>#include "ChildView.h"<br /><br />class CMainFrame : public CFrameWnd<br />{<br />　public:<br />　　CMainFrame();<br />　protected: <br />　　DECLARE_DYNAMIC(CMainFrame)<br /><br />　　// Attributes<br />　public:<br /><br />　　// Operations<br />　public:<br />　　// Overrides<br />　　// ClassWizard generated virtual function overrides<br />　　//{{AFX_VIRTUAL(CMainFrame)<br />　　　virtual BOOL PreCreateWindow(CREATESTRUCT&amp; cs);<br />　　　virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);<br />　　//}}AFX_VIRTUAL<br /><br />　　// Implementation<br />　public:<br />　　virtual ~CMainFrame();<br />　　#ifdef _DEBUG<br />　　　virtual void AssertValid() const;<br />　　　virtual void Dump(CDumpContext&amp; dc) const;<br />　　#endif<br />　　CChildView m_wndView;<br /><br />　　// Generated message map functions<br />　protected:<br />　//{{AFX_MSG(CMainFrame)<br />　　afx_msg void OnSetFocus(CWnd *pOldWnd);<br />　　// NOTE - the ClassWizard will add and remove member functions here.<br />　　// DO NOT EDIT what you see in these blocks of generated code!<br />　//}}AFX_MSG<br />　DECLARE_MESSAGE_MAP()<br />};</td></tr></tbody></table><br />　　MainFrm.cpp文件<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)<br /><br />BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)<br />　//{{AFX_MSG_MAP(CMainFrame)<br />　　// NOTE - the ClassWizard will add and remove mapping macros here.<br />　　// DO NOT EDIT what you see in these blocks of generated code !<br />　　ON_WM_SETFOCUS()<br />　//}}AFX_MSG_MAP<br />END_MESSAGE_MAP()<br /><br />/////////////////////////////////////////////////////////////////////////////<br />// CMainFrame construction/destruction<br /><br />CMainFrame::CMainFrame()<br />{<br />　// TODO: add member initialization code here<br />}<br /><br />CMainFrame::~CMainFrame()<br />{}<br /><br />BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&amp; cs)<br />{<br />　if( !CFrameWnd::PreCreateWindow(cs) )<br />　　return FALSE;<br />　　// TODO: Modify the Window class or styles here by modifying<br />　　// the CREATESTRUCT cs<br /><br />　cs.dwExStyle &amp;= ~WS_EX_CLIENTEDGE;<br />　cs.lpszClass = AfxRegisterWndClass(0);<br />　return TRUE;<br />}</td></tr></tbody></table><br />　　ChildView.h文件<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>// CChildView window<br /><br />class CChildView : public CWnd<br />{<br />　// Construction<br />　public:<br />　　CChildView();<br /><br />　　// Attributes<br />　public:<br />　　// Operations<br />　public:<br />　　// Overrides<br />　　// ClassWizard generated virtual function overrides<br />　　//{{AFX_VIRTUAL(CChildView)<br />　　　protected:<br />　　　　virtual BOOL PreCreateWindow(CREATESTRUCT&amp; cs);<br />　　//}}AFX_VIRTUAL<br /><br />　　// Implementation<br />　public:<br />　　virtual ~CChildView();<br /><br />　　// Generated message map functions<br />　protected:<br />　　//{{AFX_MSG(CChildView)<br />　　　afx_msg void OnPaint();<br />　　//}}AFX_MSG<br />　DECLARE_MESSAGE_MAP()<br />};<br /><br />ChildView.cpp文件<br />// CChildView<br /><br />CChildView::CChildView()<br />{}<br /><br />CChildView::~CChildView()<br />{}<br /><br />BEGIN_MESSAGE_MAP(CChildView,CWnd )<br />//{{AFX_MSG_MAP(CChildView)<br />ON_WM_PAINT()<br />//}}AFX_MSG_MAP<br />END_MESSAGE_MAP()<br /><br />/////////////////////////////////////////////////////////////////////////////<br />// CChildView message handlers<br /><br />BOOL CChildView::PreCreateWindow(CREATESTRUCT&amp; cs) <br />{<br />　if (!CWnd::PreCreateWindow(cs))<br />　　return FALSE;<br /><br />　cs.dwExStyle |= WS_EX_CLIENTEDGE;<br />　cs.style &amp;= ~WS_BORDER;<br />　cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,::LoadCursor(NULL, IDC_ARROW),<br />HBRUSH(COLOR_WINDOW+1),NULL);<br /><br />　return TRUE;<br />}<br /><br />void CChildView::OnPaint() <br />{<br />　CPaintDC dc(this); // device context for painting<br /><br />　// TODO: Add your message handler code here<br />　// Do not call CWnd::OnPaint() for painting messages<br />}</td></tr></tbody></table><br />　
　文件MFCThread.h和MFCThread.cpp定义和实现的类CMFCThreadApp继承自CWinApp类，而CWinApp类又继承
自CWinThread类（CWinThread类又继承自CCmdTarget类），所以CMFCThread本质上是一个MFC线程类，下图给出了相
关的类层次结构：<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://yesky.anhuinews.com/imagelist/06/01/g705u0arabo5.jpg" border="0" /></div></td></tr></tbody></table></div>
												<div>我们提取CWinApp类原型的一部分：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>class CWinApp : public CWinThread<br />{<br />　DECLARE_DYNAMIC(CWinApp)<br />　public:<br />　　// Constructor<br />　　CWinApp(LPCTSTR lpszAppName = NULL);// default app name<br />　　// Attributes<br />　　// Startup args (do not change)<br />　　HINSTANCE m_hInstance;<br />　　HINSTANCE m_hPrevInstance;<br />　　LPTSTR m_lpCmdLine;<br />　　int m_nCmdShow;<br />　　// Running args (can be changed in InitInstance)<br />　　LPCTSTR m_pszAppName; // human readable name<br />　　LPCTSTR m_pszExeName; // executable name (no spaces)<br />　　LPCTSTR m_pszHelpFilePath; // default based on module path<br />　　LPCTSTR m_pszProfileName; // default based on app name<br /><br />　　// Overridables<br />　　virtual BOOL InitApplication();<br />　　virtual BOOL InitInstance();<br />　　virtual int ExitInstance(); // return app exit code<br />　　virtual int Run();<br />　　virtual BOOL OnIdle(LONG lCount); // return TRUE if more idle processing<br />　　virtual LRESULT ProcessWndProcException(CException* e,const MSG* pMsg);<br /><br />　public:<br />　　virtual ~CWinApp();<br />　protected:<br />　　DECLARE_MESSAGE_MAP()<br />};</td></tr></tbody></table><br />　　SDK程序的WinMain 所完成的工作现在由CWinApp 的三个函数完成：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>virtual BOOL InitApplication();<br />virtual BOOL InitInstance();<br />virtual int Run();</td></tr></tbody></table><br />　
　"CMFCThreadApp theApp;"语句定义的全局变量theApp是整个程式的application object，每一个MFC
应用程序都有一个。当我们执行MFCThread程序的时候，这个全局变量被构造。theApp
配置完成后，WinMain开始执行。但是程序中并没有WinMain的代码，它在哪里呢？原来MFC早已准备好并由Linker直接加到应用程序代码中
的，其原型为（存在于VC++6.0安装目录下提供的APPMODUL.CPP文件中）：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>extern "C" int WINAPI<br />_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,<br />LPTSTR lpCmdLine, int nCmdShow)<br />{<br />　// call shared/exported WinMain<br />　return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);<br />}</td></tr></tbody></table><br />　　其中调用的AfxWinMain如下（存在于VC++6.0安装目录下提供的WINMAIN.CPP文件中）：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,<br />LPTSTR lpCmdLine, int nCmdShow)<br />{<br />　ASSERT(hPrevInstance == NULL);<br /><br />　int nReturnCode = -1;<br />　CWinThread* pThread = AfxGetThread();<br />　CWinApp* pApp = AfxGetApp();<br /><br />　// AFX internal initialization<br />　if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))<br />　　goto InitFailure;<br /><br />　// App global initializations (rare)<br />　if (pApp != NULL &amp;&amp; !pApp-&gt;InitApplication())<br />　　goto InitFailure;<br /><br />　// Perform specific initializations<br />　if (!pThread-&gt;InitInstance())<br />　{<br />　　if (pThread-&gt;m_pMainWnd != NULL)<br />　　{<br />　　　TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");<br />　　　pThread-&gt;m_pMainWnd-&gt;DestroyWindow();<br />　　}<br />　　nReturnCode = pThread-&gt;ExitInstance();<br />　　goto InitFailure;<br />　}<br />　nReturnCode = pThread-&gt;Run();<br /><br />　InitFailure:<br />　#ifdef _DEBUG<br />　　// Check for missing AfxLockTempMap calls<br />　　if (AfxGetModuleThreadState()-&gt;m_nTempMapLock != 0)<br />　　{<br />　　　TRACE1("Warning: Temp map lock count non-zero (%ld).\n",<br />AfxGetModuleThreadState()-&gt;m_nTempMapLock);<br />　　}<br />　　AfxLockTempMaps();<br />　　AfxUnlockTempMaps(-1);<br />　#endif<br /><br />　AfxWinTerm();<br />　return nReturnCode;<br />}</td></tr></tbody></table><br />　　我们提取主干，实际上，这个函数做的事情主要是：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CWinThread* pThread = AfxGetThread();<br />CWinApp* pApp = AfxGetApp();<br />AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)<br />pApp-&gt;InitApplication()<br />pThread-&gt;InitInstance()<br />pThread-&gt;Run();</td></tr></tbody></table><br />　
　其中，InitApplication
是注册窗口类别的场所；InitInstance是产生窗口并显示窗口的场所；Run是提取并分派消息的场所。这样，MFC就同WIN32
SDK程序对应起来了。CWinThread::Run是程序生命的"活水源头"（侯捷：《深入浅出MFC》，函数存在于VC++
6.0安装目录下提供的THRDCORE.CPP文件中）：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>// main running routine until thread exits<br />int CWinThread::Run()<br />{<br />　ASSERT_VALID(this);<br /><br />　// for tracking the idle time state<br />　BOOL bIdle = TRUE;<br />　LONG lIdleCount = 0;<br /><br />　// acquire and dispatch messages until a WM_QUIT message is received.<br />　for (;;)<br />　{<br />　　// phase1: check to see if we can do idle work<br />　　while (bIdle &amp;&amp; !::PeekMessage(&amp;m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))<br />　　{<br />　　　// call OnIdle while in bIdle state<br />　　　if (!OnIdle(lIdleCount++))<br />　　　　bIdle = FALSE; // assume "no idle" state<br />　　}<br /><br />　　// phase2: pump messages while available<br />　　do<br />　　{<br />　　　// pump message, but quit on WM_QUIT<br />　　　if (!PumpMessage())<br />　　　　return ExitInstance();<br /><br />　　　// reset "no idle" state after pumping "normal" message<br />　　　if (IsIdleMessage(&amp;m_msgCur))<br />　　　{<br />　　　　bIdle = TRUE;<br />　　　　lIdleCount = 0;<br />　　　}<br /><br />　　} while (::PeekMessage(&amp;m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));<br />　}<br />　ASSERT(FALSE); // not reachable<br />}</td></tr></tbody></table><br />　　其中的PumpMessage函数又对应于：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>/////////////////////////////////////////////////////////////////////////////<br />// CWinThread implementation helpers<br /><br />BOOL CWinThread::PumpMessage()<br />{<br />　ASSERT_VALID(this);<br /><br />　if (!::GetMessage(&amp;m_msgCur, NULL, NULL, NULL))<br />　{<br />　　return FALSE;<br />　}<br /><br />　// process this message<br />　if(m_msgCur.message != WM_KICKIDLE &amp;&amp; !PreTranslateMessage(&amp;m_msgCur))<br />　{<br />　　::TranslateMessage(&amp;m_msgCur);<br />　　::DispatchMessage(&amp;m_msgCur);<br />　}<br />　return TRUE;<br />}</td></tr></tbody></table><br />　　因此，忽略IDLE状态，整个RUN的执行提取主干就是：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>do {<br />　::GetMessage(&amp;msg,...);<br />　PreTranslateMessage{&amp;msg);<br />　::TranslateMessage(&amp;msg);<br />　::DispatchMessage(&amp;msg);<br />　...<br />} while (::PeekMessage(...));</td></tr></tbody></table><br />　　由此，我们建立了MFC消息获取和派生机制与WIN32 SDK程序之间的对应关系。下面继续分析MFC消息的"绕行"过程。<br /><br />　
　在MFC中，只要是CWnd 衍生类别，就可以拦下任何Windows消息。与窗口无关的MFC类别（例如CDocument
和CWinApp）如果也想处理消息，必须衍生自CCmdTarget，并且只可能收到WM_COMMAND消息。所有能进行MESSAGE_MAP的类
都继承自CCmdTarget，如：<br /><br /><table align="center" border="0" width="90%"><tbody><tr><td><div align="center"><img src="http://yesky.anhuinews.com/imagelist/06/01/4bidfnchk995.jpg" border="0" /><img src="http://yesky.anhuinews.com/imagelist/06/01/eqq6knx8w7z0.jpg" border="0" /><img src="http://yesky.anhuinews.com/imagelist/06/01/m7pbiwap6un1.jpg" border="0" /></div></td></tr></tbody></table><br />　　MFC中MESSAGE_MAP的定义依赖于以下三个宏：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>DECLARE_MESSAGE_MAP()<br /><br />BEGIN_MESSAGE_MAP( <br />　theClass, //Specifies the name of the class whose message map this is<br />　baseClass //Specifies the name of the base class of theClass<br />)<br /><br />END_MESSAGE_MAP()</td></tr></tbody></table><br />　　我们程序中涉及到的有：MFCThread.h、MainFrm.h、ChildView.h文件<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>DECLARE_MESSAGE_MAP()<br />MFCThread.cpp文件<br />BEGIN_MESSAGE_MAP(CMFCThreadApp, CWinApp)<br />//{{AFX_MSG_MAP(CMFCThreadApp)<br />ON_COMMAND(ID_APP_ABOUT, OnAppAbout)<br />// NOTE - the ClassWizard will add and remove mapping macros here.<br />// DO NOT EDIT what you see in these blocks of generated code!<br />//}}AFX_MSG_MAP<br />END_MESSAGE_MAP()<br />MainFrm.cpp文件<br />BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)<br />//{{AFX_MSG_MAP(CMainFrame)<br />// NOTE - the ClassWizard will add and remove mapping macros here.<br />// DO NOT EDIT what you see in these blocks of generated code !<br />ON_WM_SETFOCUS()<br />//}}AFX_MSG_MAP<br />END_MESSAGE_MAP()<br />ChildView.cpp文件<br />BEGIN_MESSAGE_MAP(CChildView,CWnd )<br />//{{AFX_MSG_MAP(CChildView)<br />ON_WM_PAINT()<br />//}}AFX_MSG_MAP<br />END_MESSAGE_MAP()</td></tr></tbody></table><br />　　由这些宏，MFC建立了一个消息映射表（消息流动网），按照消息流动网匹配对应的消息处理函数，完成整个消息的"绕行"。<br /><br />　　看到这里相信你有这样的疑问：程序定义了CWinApp类的theApp全局变量，可是从来没有调用AfxBeginThread或theApp.CreateThread启动线程呀，theApp对应的线程是怎么启动的？<br /><br />　　答：MFC在这里用了很高明的一招。实际上，程序开始运行，第一个线程是由操作系统（OS）启动的，在CWinApp的构造函数里，MFC将theApp"对应"向了这个线程，具体的实现是这样的：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>CWinApp::CWinApp(LPCTSTR lpszAppName)<br />{<br />　if (lpszAppName != NULL)<br />　　m_pszAppName = _tcsdup(lpszAppName);<br />　else<br />　　m_pszAppName = NULL;<br /><br />　// initialize CWinThread state<br />　AFX_MODULE_STATE *pModuleState = _AFX_CMDTARGET_GETSTATE();<br />　AFX_MODULE_THREAD_STATE *pThreadState = pModuleState-&gt;m_thread;<br />　ASSERT(AfxGetThread() == NULL);<br />　pThreadState-&gt;m_pCurrentWinThread = this;<br />　ASSERT(AfxGetThread() == this);<br />　m_hThread = ::GetCurrentThread();<br />　m_nThreadID = ::GetCurrentThreadId();<br /><br />　// initialize CWinApp state<br />　ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please<br />　pModuleState-&gt;m_pCurrentWinApp = this;<br />　ASSERT(AfxGetApp() == this);<br /><br />　// in non-running state until WinMain<br />　m_hInstance = NULL;<br />　m_pszHelpFilePath = NULL;<br />　m_pszProfileName = NULL;<br />　m_pszRegistryKey = NULL;<br />　m_pszExeName = NULL;<br />　m_pRecentFileList = NULL;<br />　m_pDocManager = NULL;<br />　m_atomApp = m_atomSystemTopic = NULL; //微软懒鬼？或者他认为 <br />　//这样连等含义更明确？<br />　m_lpCmdLine = NULL;<br />　m_pCmdInfo = NULL;<br /><br />　// initialize wait cursor state<br />　m_nWaitCursorCount = 0;<br />　m_hcurWaitCursorRestore = NULL;<br /><br />　// initialize current printer state<br />　m_hDevMode = NULL;<br />　m_hDevNames = NULL;<br />　m_nNumPreviewPages = 0; // not specified (defaults to 1)<br /><br />　// initialize DAO state<br />　m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called<br /><br />　// other initialization<br />　m_bHelpMode = FALSE;<br />　m_nSafetyPoolSize = 512; // default size<br />}</td></tr></tbody></table><br />　　很显然，theApp成员变量都被赋予OS启动的这个当前线程相关的值，如代码：<br /><br /><table align="center" bgcolor="#e3e3e3" border="1" bordercolor="#cccccc" width="90%"><tbody><tr><td>m_hThread = ::GetCurrentThread();//theApp的线程句柄等于当前线程句柄 <br />m_nThreadID = ::GetCurrentThreadId();//theApp的线程ID等于当前线程ID</td></tr></tbody></table><br />　
　所以CWinApp类几乎只是为MFC程序的第一个线程量身定制的，它不需要也不能被AfxBeginThread或
theApp.CreateThread"再次"启动。这就是CWinApp类和theApp全局变量的内涵！如果你要再增加一个UI线程，不要继承类
CWinApp，而应继承类CWinThread。而参考第1节，由于我们一般以主线程（在MFC程序里实际上就是OS启动的第一个线程）处理所有窗口的
消息，所以我们几乎没有再启动UI线程的需求！</div>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/swo2006/aggbug/11378.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-17 22:30 <a href="http://www.cppblog.com/swo2006/articles/11378.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出Win32多线程程序设计之基本概念</title><link>http://www.cppblog.com/swo2006/articles/11347.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Thu, 17 Aug 2006 07:03:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11347.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11347.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11347.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11347.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11347.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: win32多线程编程(ZT)																																												一．深入浅出Win32多线程程序设计之基本概念[转]																										引言　　从单进程单线程到多进程多线程是操作系统发展的一种必然趋势，当年的DOS系统属于单任务操作系统，最优秀的程序员也只能通过驻留内存的方式实现...&nbsp;&nbsp;<a href='http://www.cppblog.com/swo2006/articles/11347.html'>阅读全文</a><img src ="http://www.cppblog.com/swo2006/aggbug/11347.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-17 15:03 <a href="http://www.cppblog.com/swo2006/articles/11347.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>